query("SELECT * FROM fitme3070_info WHERE id = 1 LIMIT 1") ->fetch(PDO::FETCH_ASSOC) ?: []; } catch (Throwable $e) { $row = []; } foreach ($cols as $c) { if (!array_key_exists($c, $row) || $row[$c] === null) $row[$c] = ''; } return $row; } // Top navigation map (label => CI-style path). Kept identical to the original // so navbar/footer markup is unchanged; .htaccess rewrites these to site/*.php. function site_navbar(): array { // One-page layout: Home, Equipa, Modalidades, Horário, Contactos are all // anchor links on the single homepage. CrossFit is a separate page styled // differently (see navbar.php for the 'crossfit_btn' flag). return [ 'Home' => '#home', 'Equipa' => '#equipa', 'Modalidades' => '#modalidades', 'Horário' => '#horario', 'Contactos' => '#contactos', 'CrossFit' => 'home/crossfit', // separate page, navbar styles it specially ]; } function site_offer(PDO $pdo): array { try { return $pdo->query( "SELECT * FROM website_offer WHERE o_deleted_at IS NULL OR o_deleted_at = '0000-00-00 00:00:00' OR o_deleted_at = ''" )->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { return []; } } function site_work_hours(PDO $pdo): array { try { return $pdo->query("SELECT * FROM work_hours")->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { return []; } } function site_team(PDO $pdo): array { try { return $pdo->query("SELECT * FROM team WHERE deleted_at IS NULL")->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { return []; } } function site_modalidades(PDO $pdo): array { try { return $pdo->query( "SELECT * FROM modalidades WHERE deleted_at IS NULL ORDER BY item_order DESC" )->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { return []; } } // Currently-visible time-limited events for the homepage banner. Thin wrapper // over db_events_active() (functions_events.php) so the site code reads in the // same site_*() style as everything else here. function site_active_events(PDO $pdo): array { return function_exists('db_events_active') ? db_events_active($pdo) : []; } // ─── Image-path resolver ────────────────────────────────────────────────────── // DB stores either a bare filename ("1.jpg") or a full relative path // ("uploads/team/foto/1.jpg"). This normalises both to a working URL. // $base_dir is the upload subdirectory (e.g. "uploads/team/foto"). function site_img_url($value, $base_dir): string { // Coerce null/empty to empty string $value = (string) $value; if ($value === '') return ''; // Already a full URL if (substr($value, 0, 4) === 'http') return $value; // Already has the uploads/ prefix — use as-is if (substr($value, 0, 8) === 'uploads/') return base_url($value); // Bare filename — prepend the base directory return base_url(rtrim((string) $base_dir, '/') . '/' . ltrim($value, '/')); } // Schedule joined to modalidades (name/colour/icon), optionally filtered by // local (e.g. 'crossfit'). Mirrors Horario_model::getAll(). function site_horario(PDO $pdo, string $local = ''): array { $sql = "SELECT h.*, TIME_FORMAT(h.hora_inicio, '%H:%i') AS hora_inicio, TIME_FORMAT(h.hora_fim, '%H:%i') AS hora_fim, m.nome, m.cor, m.icon FROM horario h JOIN modalidades m ON m.m_id = h.id_modalidade"; $args = []; if ($local !== '') { $sql .= " WHERE h.local = ?"; $args[] = $local; } $sql .= " ORDER BY h.hora_inicio ASC, m.nome ASC"; try { $st = $pdo->prepare($sql); $st->execute($args); return $st->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { return []; } }