Apply strict_types and extensive type declarations throughout the API and models, improving type safety and error handling. Key changes: add declare(strict_types=1) to many files; convert properties, method parameters and return values to typed signatures (PDO, arrays, ints, strings, bools, nullables); switch exception handling to Throwable in index and Router; improve Router, controllers and model method signatures and nullability handling; refine file/image serving security checks and headers in ImageController; strengthen Database typing and initialization methods; return explicit types from BaseModel CRUD helpers and counting; update Media/Cast/Adult/Game/Console/Settings controllers and models to use typed methods, better validation, and clearer update/create return types. Also add AGENTS.md (agent skills index), update README with Swagger/OpenAPI usage instructions, and add /.windsurf to .gitignore. These changes aim to harden runtime correctness, make intended contracts explicit, and prepare the codebase for easier maintenance and static analysis.
259 lines
10 KiB
PHP
259 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../models/Cast.php';
|
|
require_once __DIR__ . '/../models/AdultCast.php';
|
|
require_once __DIR__ . '/../services/ApiLogger.php';
|
|
|
|
class CastController {
|
|
private Cast $cast;
|
|
private AdultCast $adultCast;
|
|
private ApiLogger $logger;
|
|
|
|
public function __construct(PDO $pdo) {
|
|
$this->cast = new Cast($pdo);
|
|
$this->adultCast = new AdultCast($pdo);
|
|
$this->logger = ApiLogger::getInstance();
|
|
}
|
|
|
|
public function handleRequest(string $method, array $segments): array {
|
|
$id = isset($segments[1]) ? (int)$segments[1] : null;
|
|
$subResource = isset($segments[2]) ? $segments[2] : null;
|
|
|
|
$path = '/' . implode('/', $segments);
|
|
$this->logger->logRequest($method, $path);
|
|
// Adult-spezifische Endpunkte
|
|
if ($id === 'adult' || $subResource === 'adult') {
|
|
// die("adult");
|
|
return $this->handleAdult($method, $id, $segments);
|
|
}
|
|
|
|
switch ($method) {
|
|
case 'GET':
|
|
return $id ? $this->getOne($id, $segments) : $this->getAll();
|
|
case 'POST':
|
|
return $this->create();
|
|
case 'PUT':
|
|
return $this->update($id);
|
|
case 'DELETE':
|
|
return $this->delete($id);
|
|
default:
|
|
http_response_code(405);
|
|
return ['success' => false, 'error' => 'Method not allowed'];
|
|
}
|
|
}
|
|
|
|
private function handleAdult(string $method, ?int $id, array $segments): array {
|
|
|
|
switch ($method) {
|
|
case 'GET':
|
|
if ($id) {
|
|
return $this->getAdultOne($id);
|
|
}
|
|
return $this->getAdultAll();
|
|
case 'POST':
|
|
return $this->createAdult();
|
|
case 'PUT':
|
|
return $this->updateAdult($id);
|
|
case 'DELETE':
|
|
return $this->deleteAdultSpecifics($id);
|
|
default:
|
|
http_response_code(405);
|
|
return ['success' => false, 'error' => 'Method not allowed'];
|
|
}
|
|
}
|
|
|
|
private function getAdultAll(): array {
|
|
$filters = [];
|
|
if (isset($_GET['search'])) $filters['search'] = $_GET['search'];
|
|
if (isset($_GET['ethnicity'])) $filters['ethnicity'] = $_GET['ethnicity'];
|
|
if (isset($_GET['hair_color'])) $filters['hair_color'] = $_GET['hair_color'];
|
|
|
|
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
|
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 20;
|
|
|
|
$result = $this->adultCast->searchAdultActors($filters, $page, $limit);
|
|
return ['success' => true, 'data' => $result];
|
|
}
|
|
|
|
private function getAdultOne(?int $id): array {
|
|
$cast = $this->adultCast->getWithAdultSpecifics($id);
|
|
if (!$cast) {
|
|
http_response_code(404);
|
|
return ['success' => false, 'error' => 'Adult actor not found'];
|
|
}
|
|
return ['success' => true, 'data' => $cast];
|
|
}
|
|
|
|
private function createAdult(): array {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
if (!$data) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Invalid JSON'];
|
|
}
|
|
|
|
$name = $data['name'] ?? null;
|
|
if (!$name) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Name is required'];
|
|
}
|
|
|
|
// Prüfen ob bereits Eintrag mit diesem cleanname existiert
|
|
$cleanname = generateCleanName($name);
|
|
$existing = $this->cast->findByCleanName($cleanname);
|
|
|
|
if ($existing) {
|
|
// Update existing cast member with new photo if provided
|
|
if (isset($data['photo']) && !empty($data['photo'])) {
|
|
$this->adultCast->updateWithAdultSpecifics($existing['id'], $data);
|
|
}
|
|
http_response_code(200);
|
|
$this->logger->logRequest('POST', '/api/cast/adult', [], $data);
|
|
$this->logger->logResponse('POST', '/api/cast/adult', 200, ['id' => $existing['id'], 'message' => 'Cast already exists']);
|
|
return ['success' => true, 'data' => ['id' => $existing['id'], 'message' => 'Cast already exists']];
|
|
}
|
|
|
|
$castId = $this->adultCast->createWithAdultSpecifics($data);
|
|
http_response_code(201);
|
|
$this->logger->logRequest('POST', '/api/cast/adult', [], $data);
|
|
$this->logger->logResponse('POST', '/api/cast/adult', 201, ['id' => $castId]);
|
|
return ['success' => true, 'data' => ['id' => $castId]];
|
|
}
|
|
|
|
private function updateAdult(?int $id): array {
|
|
if (!$id) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'ID required'];
|
|
}
|
|
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
if (!$data) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Invalid JSON'];
|
|
}
|
|
|
|
$this->adultCast->updateWithAdultSpecifics($id, $data);
|
|
$this->logger->logRequest('PUT', "/api/cast/adult/$id", [], $data);
|
|
$this->logger->logResponse('PUT', "/api/cast/adult/$id", 200, ['id' => $id]);
|
|
return ['success' => true, 'data' => ['id' => $id]];
|
|
}
|
|
|
|
private function deleteAdultSpecifics(?int $id): array {
|
|
if (!$id) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'ID required'];
|
|
}
|
|
|
|
$deleted = $this->adultCast->deleteAdultSpecifics($id);
|
|
if (!$deleted) {
|
|
http_response_code(404);
|
|
return ['success' => false, 'error' => 'Adult specifics not found'];
|
|
}
|
|
$this->logger->logRequest('DELETE', "/api/cast/adult/$id", [], null);
|
|
$this->logger->logResponse('DELETE', "/api/cast/adult/$id", 200, ['message' => 'Adult specifics deleted successfully']);
|
|
return ['success' => true, 'message' => 'Adult specifics deleted successfully'];
|
|
}
|
|
private function getOne(?int $id, array $segments): array {
|
|
// Prüfen ob /media angehängt wurde
|
|
if (isset($segments[2]) && $segments[2] === 'media') {
|
|
return $this->getMedia($id);
|
|
}
|
|
|
|
$cast = $this->cast->getWithFilmography($id);
|
|
$cast['adult_specifics'] = $this->adultCast->getAdultSpecifics($id);
|
|
|
|
|
|
if (!$cast) {
|
|
http_response_code(404);
|
|
return ['success' => false, 'error' => 'Cast member not found'];
|
|
}
|
|
return ['success' => true, 'data' => $cast];
|
|
}
|
|
|
|
private function getMedia(?int $castId): array {
|
|
$media = $this->cast->getMediaForCast($castId);
|
|
return ['success' => true, 'data' => ['items' => $media]];
|
|
}
|
|
|
|
private function getAll(): array {
|
|
$filters = [];
|
|
if (isset($_GET['search'])) $filters['search'] = $_GET['search'];
|
|
|
|
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
|
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 20;
|
|
|
|
$result = $this->cast->search($filters, $page, $limit);
|
|
return ['success' => true, 'data' => $result];
|
|
}
|
|
|
|
private function create(): array {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
if (!$data) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Invalid JSON'];
|
|
}
|
|
|
|
$name = $data['name'] ?? null;
|
|
if (!$name) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Name is required'];
|
|
}
|
|
|
|
// Prüfen ob bereits Eintrag mit diesem cleanname existiert
|
|
$cleanname = generateCleanName($name);
|
|
$existing = $this->cast->findByCleanName($cleanname);
|
|
|
|
if ($existing) {
|
|
// Update existing cast member with new photo if provided
|
|
if (isset($data['photo']) && !empty($data['photo'])) {
|
|
$this->cast->updateWithOccupations($existing['id'], $data);
|
|
}
|
|
http_response_code(200);
|
|
$this->logger->logRequest('POST', '/api/cast', [], $data);
|
|
$this->logger->logResponse('POST', '/api/cast', 200, ['id' => $existing['id'], 'message' => 'Cast already exists']);
|
|
return ['success' => true, 'data' => ['id' => $existing['id'], 'message' => 'Cast already exists']];
|
|
}
|
|
|
|
$castId = $this->cast->createWithOccupations($data);
|
|
http_response_code(201);
|
|
$this->logger->logRequest('POST', '/api/cast', [], $data);
|
|
$this->logger->logResponse('POST', '/api/cast', 201, ['id' => $castId]);
|
|
return ['success' => true, 'data' => ['id' => $castId]];
|
|
}
|
|
|
|
private function update(?int $id): array {
|
|
if (!$id) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'ID required'];
|
|
}
|
|
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
if (!$data) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'Invalid JSON'];
|
|
}
|
|
|
|
$this->cast->updateWithOccupations($id, $data);
|
|
$this->logger->logRequest('PUT', "/api/cast/$id", [], $data);
|
|
$this->logger->logResponse('PUT', "/api/cast/$id", 200, ['id' => $id]);
|
|
return ['success' => true, 'data' => ['id' => $id]];
|
|
}
|
|
|
|
private function delete(?int $id): array {
|
|
if (!$id) {
|
|
http_response_code(400);
|
|
return ['success' => false, 'error' => 'ID required'];
|
|
}
|
|
|
|
$deleted = $this->cast->delete($id);
|
|
if (!$deleted) {
|
|
http_response_code(404);
|
|
return ['success' => false, 'error' => 'Cast member not found'];
|
|
}
|
|
$this->logger->logRequest('DELETE', "/api/cast/$id", [], null);
|
|
$this->logger->logResponse('DELETE', "/api/cast/$id", 200, ['message' => 'Cast member deleted successfully']);
|
|
return ['success' => true, 'message' => 'Cast member deleted successfully'];
|
|
}
|
|
}
|