query($sql)->fetchAll(PDO::FETCH_ASSOC); $boxes = DB::pdo() ->query('SELECT * FROM shelter_boxes ORDER BY sort_order,name COLLATE NOCASE') ->fetchAll(PDO::FETCH_ASSOC); foreach ($rooms as &$room) { $room['boxes'] = array_values( array_filter( $boxes, static fn($box) => (int) $box['room_id'] === (int) $room['id'] && (!$activeOnly || (int) $box['active'] === 1), ), ); } return $rooms; } public static function byCode(bool $activeOnly = true): array { $result = []; foreach (self::all($activeOnly) as $room) { $result[(string) $room['code']] = $room; } return $result; } public static function resolveAnimal(array $animal, array $rooms): string { $stored = (string) ($animal['refuge_room'] ?? ''); if ($stored !== '' && isset($rooms[$stored])) { return $stored; } $status = (string) ($animal['status'] ?? 'refuge'); foreach ($rooms as $code => $room) { if ((string) $room['status_code'] === $status) { return (string) $code; } } return array_key_first($rooms) ?? ''; } public static function normalizeCode(string $value): string { $value = mb_strtolower(trim($value)); $value = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $value) ?: $value; return trim(preg_replace('/[^a-z0-9]+/', '-', $value) ?? '', '-'); } public static function periods(array $room): array { $periods = array_values(array_intersect( self::PERIODS, explode(',', (string) ($room['care_periods'] ?? 'morning,evening')), )); return $periods ?: ['morning', 'evening']; } public static function accepts(array $room, array $animal): bool { $species = trim((string) ($room['allowed_species'] ?? '')); $sex = trim((string) ($room['allowed_sex'] ?? '')); $fiv = (string) ($room['required_fiv'] ?? 'any'); if ($species !== '' && SpeciesService::normalize((string) ($animal['species'] ?? '')) !== $species) { return false; } if ($sex !== '' && (string) ($animal['sex'] ?? '') !== $sex) { return false; } $positive = (int) ($animal['fiv'] ?? 0) === 1 || (string) ($animal['fiv_status'] ?? '') === 'positive'; return $fiv === 'any' || ($fiv === 'positive' ? $positive : !$positive); } }