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.
298 lines
13 KiB
PHP
298 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/Cast.php';
|
|
require_once __DIR__ . '/../services/ApiLogger.php';
|
|
|
|
class AdultCast extends Cast {
|
|
|
|
public function getWithAdultSpecifics(?int $id): ?array {
|
|
$cast = $this->getWithFilmography($id);
|
|
if (!$cast) {
|
|
return null;
|
|
}
|
|
|
|
$cast['adult_specifics'] = $this->getAdultSpecifics($id);
|
|
|
|
return $cast;
|
|
}
|
|
|
|
public function getAdultSpecifics(?int $castId): array|false {
|
|
$stmt = $this->pdo->prepare("SELECT * FROM adult_cast_specifics WHERE cast_id = ?");
|
|
$stmt->execute([$castId]);
|
|
return $stmt->fetch();
|
|
}
|
|
|
|
public function createWithAdultSpecifics(array $data): int {
|
|
ApiLogger::getInstance()->logDebug("AdultCast createWithAdultSpecifics called with data: " . json_encode($data));
|
|
|
|
$name = $data['name'] ?? null;
|
|
if (!$name) {
|
|
throw new Exception('Name is required');
|
|
}
|
|
|
|
// cleanname generieren
|
|
$cleanname = generateCleanName($name);
|
|
|
|
// Process photo field (base64 to file path)
|
|
$data = $this->processPhotoField($data);
|
|
|
|
// Zuerst Basis-Cast erstellen
|
|
$castData = [
|
|
'name' => $name,
|
|
'cleanname' => $cleanname,
|
|
'photo' => $data['photo'] ?? null,
|
|
'bio' => $data['bio'] ?? null,
|
|
'birthDate' => $data['birthDate'] ?? null,
|
|
'birthPlace' => $data['birthPlace'] ?? null
|
|
];
|
|
|
|
$castId = (int)$this->create($castData);
|
|
ApiLogger::getInstance()->logDebug("AdultCast createWithAdultSpecifics: Base cast created with id: $castId");
|
|
|
|
// Occupations speichern
|
|
if (isset($data['occupations']) && is_array($data['occupations'])) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast createWithAdultSpecifics: Saving occupations: " . json_encode($data['occupations']));
|
|
$this->saveRelatedItems('occupations', $castId, $data['occupations'], 'cast_id');
|
|
}
|
|
|
|
// Adult-spezifische Daten speichern
|
|
if (isset($data['adult_specifics']) && is_array($data['adult_specifics'])) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast createWithAdultSpecifics: Saving adult_specifics");
|
|
$this->saveAdultSpecifics($castId, $data['adult_specifics']);
|
|
} else {
|
|
ApiLogger::getInstance()->logDebug("AdultCast createWithAdultSpecifics: No adult_specifics found in data");
|
|
}
|
|
|
|
return $castId;
|
|
}
|
|
|
|
public function updateWithAdultSpecifics(int $id, array $data): bool {
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics called with id: $id, data: " . json_encode($data));
|
|
|
|
// Set update flag for image replacement
|
|
$this->isUpdate = true;
|
|
$this->castId = $id;
|
|
|
|
// Process photo field (base64 to file path)
|
|
$data = $this->processPhotoField($data);
|
|
|
|
// Basis-Cast aktualisieren
|
|
$castData = [];
|
|
foreach (['name', 'photo', 'bio', 'birthDate', 'birthPlace'] as $field) {
|
|
if (array_key_exists($field, $data)) {
|
|
$castData[$field] = $data[$field];
|
|
}
|
|
}
|
|
|
|
if (!empty($castData)) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics: Updating base cast data: " . json_encode($castData));
|
|
$this->update($id, $castData);
|
|
}
|
|
|
|
// Occupations aktualisieren
|
|
if (isset($data['occupations']) && is_array($data['occupations'])) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics: Updating occupations: " . json_encode($data['occupations']));
|
|
$this->pdo->prepare("DELETE FROM occupations WHERE cast_id = ?")->execute([$id]);
|
|
$this->saveRelatedItems('occupations', $id, $data['occupations'], 'cast_id');
|
|
}
|
|
|
|
// Adult-spezifische Daten aktualisieren
|
|
if (isset($data['adult_specifics']) && is_array($data['adult_specifics'])) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics: Saving adult_specifics");
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics: adult_specifics data: " . json_encode($data['adult_specifics']));
|
|
$this->saveAdultSpecifics($id, $data['adult_specifics']);
|
|
} else {
|
|
ApiLogger::getInstance()->logDebug("AdultCast updateWithAdultSpecifics: No adult_specifics found in data");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected function saveAdultSpecifics(int $castId, array $specifics): void {
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics called for cast_id: $castId");
|
|
ApiLogger::getInstance()->logDebug("Specifics data: " . json_encode($specifics));
|
|
|
|
// Prüfen ob bereits Eintrag existiert
|
|
$stmt = $this->pdo->prepare("SELECT * FROM adult_cast_specifics WHERE cast_id = ?");
|
|
$stmt->execute([$castId]);
|
|
$existing = $stmt->fetch();
|
|
|
|
ApiLogger::getInstance()->logDebug("Existing entry: " . ($existing ? 'yes' : 'no'));
|
|
|
|
$fields = ['bust_size', 'cup_size', 'waist_size', 'hip_size', 'height', 'weight',
|
|
'hair_color', 'eye_color', 'ethnicity', 'tattoos', 'piercings', 'measurements', 'shoe_size'];
|
|
|
|
if ($existing) {
|
|
// Update
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Existing entry found, doing UPDATE");
|
|
$updateFields = [];
|
|
$params = [];
|
|
foreach ($fields as $field) {
|
|
if (array_key_exists($field, $specifics)) {
|
|
$updateFields[] = "$field = ?";
|
|
$params[] = $specifics[$field];
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Found field $field with value: " . json_encode($specifics[$field] ?? 'null'));
|
|
}
|
|
}
|
|
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Update fields: " . implode(', ', $updateFields));
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Total update fields count: " . count($updateFields));
|
|
|
|
if (!empty($updateFields)) {
|
|
$params[] = $castId;
|
|
$query = "UPDATE adult_cast_specifics SET " . implode(', ', $updateFields) . " WHERE cast_id = ?";
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Executing query: $query");
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: With params: " . json_encode($params));
|
|
$stmt = $this->pdo->prepare($query);
|
|
try {
|
|
$stmt->execute($params);
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: UPDATE successful");
|
|
} catch (Exception $e) {
|
|
// Fehler loggen
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics Error: " . $e->getMessage());
|
|
ApiLogger::getInstance()->logDebug("Query: $query");
|
|
ApiLogger::getInstance()->logDebug("Params: " . json_encode($params));
|
|
}
|
|
} else {
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: No fields to update");
|
|
}
|
|
} else {
|
|
// Insert
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: No existing entry, doing INSERT");
|
|
$insertFields = [];
|
|
$values = [];
|
|
$params = [];
|
|
|
|
$insertFields[] = 'cast_id';
|
|
$values[] = '?';
|
|
$params[] = $castId;
|
|
|
|
foreach ($fields as $field) {
|
|
if (array_key_exists($field, $specifics)) {
|
|
$insertFields[] = $field;
|
|
$values[] = '?';
|
|
$params[] = $specifics[$field];
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Found field $field with value: " . json_encode($specifics[$field] ?? 'null'));
|
|
}
|
|
}
|
|
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Insert fields: " . implode(', ', $insertFields));
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Total fields count: " . count($insertFields));
|
|
|
|
if (count($insertFields) > 1) {
|
|
$query = "INSERT INTO adult_cast_specifics (" . implode(', ', $insertFields) . ") VALUES (" . implode(', ', $values) . ")";
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Executing query: $query");
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: With params: " . json_encode($params));
|
|
$stmt = $this->pdo->prepare($query);
|
|
try {
|
|
$stmt->execute($params);
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: INSERT successful");
|
|
} catch (Exception $e) {
|
|
// Fehler loggen
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics Error: " . $e->getMessage());
|
|
ApiLogger::getInstance()->logDebug("Query: " . $query);
|
|
ApiLogger::getInstance()->logDebug("Params: " . json_encode($params));
|
|
}
|
|
} else {
|
|
// Keine Felder zum Speichern
|
|
ApiLogger::getInstance()->logDebug("AdultCast saveAdultSpecifics: Keine Felder zum Speichern für cast_id $castId");
|
|
}
|
|
}
|
|
}
|
|
|
|
public function deleteAdultSpecifics(?int $castId): bool {
|
|
$stmt = $this->pdo->prepare("DELETE FROM adult_cast_specifics WHERE cast_id = ?");
|
|
$stmt->execute([$castId]);
|
|
return $stmt->rowCount() > 0;
|
|
}
|
|
|
|
public function searchAdultActors(array $filters = [], int $page = 1, int $limit = 2000000000): array {
|
|
// Adult Actors mit Specifics suchen
|
|
$query = "
|
|
SELECT cs.*,
|
|
acs.bust_size, acs.cup_size, acs.waist_size, acs.hip_size,
|
|
acs.height, acs.weight, acs.hair_color, acs.eye_color, acs.ethnicity
|
|
FROM cast_staff cs
|
|
LEFT JOIN adult_cast_specifics acs ON cs.id = acs.cast_id
|
|
WHERE acs.cast_id IS NOT NULL
|
|
";
|
|
$params = [];
|
|
|
|
if (isset($filters['search'])) {
|
|
$query .= " AND cs.name LIKE ?";
|
|
$params[] = "%" . $filters['search'] . "%";
|
|
}
|
|
|
|
if (isset($filters['ethnicity'])) {
|
|
$query .= " AND acs.ethnicity = ?";
|
|
$params[] = $filters['ethnicity'];
|
|
}
|
|
|
|
if (isset($filters['hair_color'])) {
|
|
$query .= " AND acs.hair_color = ?";
|
|
$params[] = $filters['hair_color'];
|
|
}
|
|
|
|
$query .= " ORDER BY cs.createdAt DESC";
|
|
|
|
$offset = ($page - 1) * $limit;
|
|
$query .= " LIMIT " . (int)2000000000000 . " OFFSET " . (int)$offset;
|
|
|
|
$stmt = $this->pdo->prepare($query);
|
|
$stmt->execute($params);
|
|
$items = $stmt->fetchAll();
|
|
ApiLogger::getInstance()->logDebug("AdultCast searchAdultActors: Found " . count($items) . " cast members");
|
|
foreach ($items as $item) {
|
|
ApiLogger::getInstance()->logDebug("AdultCast searchAdultActors: Cast ID {$item['id']} - {$item['name']}");
|
|
}
|
|
|
|
// Occupations und Filmography für jeden laden
|
|
foreach ($items as &$item) {
|
|
$item['occupations'] = $this->getRelatedItems('occupations', $item['id'], 'cast_id');
|
|
// Add filmography information
|
|
$item['filmography'] = $this->getMediaForCast($item['id']);
|
|
// Extract unique media types
|
|
$mediaTypes = array_unique(array_column($item['filmography'], 'category'));
|
|
$item['media_types'] = array_values($mediaTypes);
|
|
ApiLogger::getInstance()->logDebug("AdultCast searchAdultActors: Cast ID {$item['id']} has " . count($item['filmography']) . " filmography items");
|
|
}
|
|
|
|
// Total count
|
|
$countQuery = "
|
|
SELECT COUNT(*)
|
|
FROM cast_staff cs
|
|
INNER JOIN adult_cast_specifics acs ON cs.id = acs.cast_id
|
|
WHERE 1=1
|
|
";
|
|
$countParams = [];
|
|
|
|
if (isset($filters['search'])) {
|
|
$countQuery .= " AND cs.name LIKE ?";
|
|
$countParams[] = "%" . $filters['search'] . "%";
|
|
}
|
|
|
|
if (isset($filters['ethnicity'])) {
|
|
$countQuery .= " AND acs.ethnicity = ?";
|
|
$countParams[] = $filters['ethnicity'];
|
|
}
|
|
|
|
if (isset($filters['hair_color'])) {
|
|
$countQuery .= " AND acs.hair_color = ?";
|
|
$countParams[] = $filters['hair_color'];
|
|
}
|
|
|
|
$countStmt = $this->pdo->prepare($countQuery);
|
|
$countStmt->execute($countParams);
|
|
$total = $countStmt->fetchColumn();
|
|
|
|
return [
|
|
'items' => $items,
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit
|
|
];
|
|
}
|
|
}
|