Files
MovieLog_Server/lib/movies.php
T
laoyang dd957d45bd refactor: 拆分 config.php 为 lib/ 模块,消除页面层重复代码
纯结构性重构,不改变任何功能。

- config.php 由 739 行缩减为 42 行,改为纯引导入口;新增 ROOT_DIR 常量
  统一拼接绝对路径(lib/ 内模块的 __DIR__ 会指向 lib/,必须替换)
- 新增 lib/ 五个模块 db.php / helpers.php / auth.php / movies.php / stats.php,
  由 config.php 按 db → helpers → auth → movies → stats 顺序加载
- add.php、edit.php 各自约 80 行重复的 POST 处理改为调用
  resolveCinemaId / resolvePersonIds / linkViewers / uploadImageFile /
  saveBase64Image / uploadMultiplePhotos / deleteStoredFile
- cinemas.php、persons.php 中重复 4 次的颜色校验改用 normalizeHexColor()
- toggleNewViewer / removeViewerRow / toggleNewCinema 下沉至 js/main.js,
  add.php 中的 removeViewer 统一更名为 removeViewerRow
- 删除死代码:imageUrl()(全项目无调用);cinemas.php 配色数组中本就会被
  array_slice 丢弃的 extra 颜色逻辑,简化为单条扁平 50 元素数组
- README 目录结构补充 lib/ 说明

验证方式:以便携 PHP 8.4 搭建 A/B 回归环境,播种固定数据后遍历 47 个
GET/POST 端点录制「状态码 + 响应体」。重构前后 42 个逐字节相同、2 个仅
上传文件名时间戳不同、3 个差异均为内联脚本下沉(已单独校验函数体逐字符
等价,剥离脚本后 HTML 标记完全一致)。24 个 PHP 文件语法检查全部通过。
2026-09-21 12:56:30 +08:00

197 lines
6.5 KiB
PHP

<?php
// ============================================
// 文件: lib/movies.php
// 说明: 电影 / 影院读取与搜索,以及表单提交时的关联数据处理
// ============================================
// ===== 电影列表 =====
function getMovies() {
$db = getDB();
$stmt = $db->query("
SELECT m.*, c.place, c.name as cinema_name, c.address as cinema_address, c.color as cinema_color
FROM movies m
LEFT JOIN cinemas c ON m.cinema_id = c.id
ORDER BY m.watch_date DESC, m.created_at DESC
");
$movies = $stmt->fetchAll();
attachViewersToMovies($movies);
return $movies;
}
function getMovie($id) {
$db = getDB();
$stmt = $db->prepare("
SELECT m.*, c.place, c.name as cinema_name, c.address as cinema_address, c.color as cinema_color
FROM movies m
LEFT JOIN cinemas c ON m.cinema_id = c.id
WHERE m.id = ?
");
$stmt->execute([$id]);
$movie = $stmt->fetch();
if ($movie) {
$stmt2 = $db->prepare("
SELECT v.id, v.movie_id, v.person_id,
COALESCE(p.name, v.name) as name,
p.color as person_color,
p.avatar as person_avatar
FROM viewers v
LEFT JOIN persons p ON v.person_id = p.id
WHERE v.movie_id = ?
ORDER BY v.id
");
$stmt2->execute([$id]);
$movie['viewers'] = $stmt2->fetchAll();
$stmt3 = $db->prepare("SELECT * FROM movie_photos WHERE movie_id = ? ORDER BY id");
$stmt3->execute([$id]);
$movie['photos'] = $stmt3->fetchAll();
}
return $movie;
}
function attachViewersToMovies(&$movies) {
if (empty($movies)) return;
$db = getDB();
$movie_ids = array_column($movies, 'id');
if (empty($movie_ids)) return;
$placeholders = implode(',', array_fill(0, count($movie_ids), '?'));
$stmt = $db->prepare("
SELECT v.movie_id, p.id as person_id, p.name, p.color, p.avatar
FROM viewers v
LEFT JOIN persons p ON v.person_id = p.id
WHERE v.movie_id IN ($placeholders)
ORDER BY v.id
");
$stmt->execute($movie_ids);
$rows = $stmt->fetchAll();
$viewers_map = [];
foreach ($rows as $row) {
$movie_id = $row['movie_id'];
if (!isset($viewers_map[$movie_id])) $viewers_map[$movie_id] = [];
$viewers_map[$movie_id][] = [
'person_id' => $row['person_id'],
'name' => $row['name'] ?? '未知',
'color' => $row['color'] ?? '#888888',
'avatar' => $row['avatar']
];
}
foreach ($movies as &$movie) {
$movie['viewers'] = $viewers_map[$movie['id']] ?? [];
}
}
// ===== 影院 =====
function getCinemas() {
$db = getDB();
$stmt = $db->query("SELECT * FROM cinemas ORDER BY place, name");
return $stmt->fetchAll();
}
// ===== 搜索 =====
function searchMovies($keyword) {
return advancedSearch(['title' => $keyword]);
}
function advancedSearch($params) {
$db = getDB();
$sql = "
SELECT DISTINCT m.*,
c.place, c.name as cinema_name, c.address as cinema_address, c.color as cinema_color
FROM movies m
LEFT JOIN cinemas c ON m.cinema_id = c.id
LEFT JOIN viewers v ON m.id = v.movie_id
LEFT JOIN persons p ON v.person_id = p.id
WHERE 1=1
";
$bind = [];
if (!empty($params['title'])) {
$sql .= " AND m.title LIKE :title";
$bind[':title'] = '%' . $params['title'] . '%';
}
if (!empty($params['cinema_id']) && is_numeric($params['cinema_id'])) {
$sql .= " AND m.cinema_id = :cinema_id";
$bind[':cinema_id'] = (int)$params['cinema_id'];
}
if (!empty($params['person_id']) && is_numeric($params['person_id'])) {
$sql .= " AND v.person_id = :person_id";
$bind[':person_id'] = (int)$params['person_id'];
}
if (!empty($params['date_from'])) {
$sql .= " AND m.watch_date >= :date_from";
$bind[':date_from'] = $params['date_from'];
}
if (!empty($params['date_to'])) {
$sql .= " AND m.watch_date <= :date_to";
$bind[':date_to'] = $params['date_to'];
}
$sql .= " ORDER BY m.watch_date DESC, m.created_at DESC";
$stmt = $db->prepare($sql);
$stmt->execute($bind);
$movies = $stmt->fetchAll();
attachViewersToMovies($movies);
return $movies;
}
// ===== 表单提交时的关联数据处理 =====
/**
* 解析表单提交的电影院选择。
* 选择「新建」且填了名称时创建影院并返回新 id;未选择或信息不足时返回 null。
*/
function resolveCinemaId($cinema_id, $new_place, $new_name, $new_address) {
$db = getDB();
if ($cinema_id === 'new' && !empty($new_name)) {
$stmt = $db->prepare("INSERT INTO cinemas (place, name, address) VALUES (?, ?, ?)");
$stmt->execute([$new_place, $new_name, $new_address]);
$cinema_id = $db->lastInsertId();
} elseif ($cinema_id === 'new') {
$cinema_id = null;
} elseif (!empty($cinema_id) && is_numeric($cinema_id)) {
$cinema_id = (int)$cinema_id;
} else {
$cinema_id = null;
}
return $cinema_id;
}
/**
* 解析「一起看的人」表单行:已有观影人取 id,选择「新增」则按姓名建库或复用。
* 返回去重后的观影人 id 列表。
*/
function resolvePersonIds($viewer_selects, $viewer_news) {
$db = getDB();
$person_ids = [];
foreach ($viewer_selects as $idx => $val) {
if ($val === 'new') {
$new_name = trim($viewer_news[$idx] ?? '');
if (!empty($new_name)) {
$chk = $db->prepare("SELECT id FROM persons WHERE name = ?");
$chk->execute([$new_name]);
$existing = $chk->fetch();
if ($existing) {
$person_ids[] = $existing['id'];
} else {
$ins = $db->prepare("INSERT INTO persons (name) VALUES (?)");
$ins->execute([$new_name]);
$person_ids[] = $db->lastInsertId();
}
}
} elseif (is_numeric($val) && $val > 0) {
$person_ids[] = (int)$val;
}
}
return array_unique($person_ids);
}
// 把观影人写入电影关联表
function linkViewers($movie_id, $person_ids) {
if (empty($person_ids)) return;
$db = getDB();
$stmt = $db->prepare("INSERT INTO viewers (movie_id, person_id, name) VALUES (?, ?, ?)");
foreach ($person_ids as $pid) {
$stmt->execute([$movie_id, $pid, '']);
}
}