Koillection 1.8.5 常用 CLI 命令与工具详解

逐条实测 Koillection 1.8.5 命令行工具:应用维护五命令、JWT 密钥与令牌、密码哈希与管理员重置闭环、双方言迁移机制与「Out-of-date 52 条」解读、SQL 直查与路由缓存调试,全部回显来自 Debian 13 + PHP 8.5.12 实机。

KoillectionKoillectionPHP 编程NAS 自托管2026/10/28

Koillection 1.8.5 常用 CLI 命令与工具详解

目标:把 Koillection 1.8.5 自带的命令行工具箱一次讲全——应用维护五命令(app 命名空间)、JWT 密钥与令牌工具(lexik 命名空间)、密码哈希与管理员重置闭环(security + dbal)、双方言迁移机制与「Out-of-date 52 条」之谜(doctrine 命名空间)、SQL 直查与路由缓存调试,每条命令附真实回显与使用建议。全部命令实测自 《Koillection 1.8.5 安装部署指南》完成的 Debian 13 + PHP 8.5.12 + PostgreSQL 17 服务器(2026-10-28),配置层参数见 《Koillection 1.8.5 配置参数详解》,组件背景见 《Koillection 1.8.5 介绍与选型指南》。

一、命令行入口与全景清单

Koillection 基于 Symfony 框架,所有命令行能力都收敛在一个入口:应用根目录下的 bin/console,用 PHP 直接执行。本章先看清这个入口的全局选项、完整命令清单和运行环境自报,后面各章再按命名空间逐条实测。

1.1 入口与全局选项

所有命令都在部署目录下执行(本文实测目录为 /opt/koillection,以具备该目录写权限的用户运行):

cd /opt/koillection && php bin/console --version

实测回显:

Symfony 8.0.13 (env: prod, debug: false)

横幅里的 env: prod, debug: false 同时确认了 .env 中 APP_ENV 与 APP_DEBUG 两项配置的真实生效值(参数含义见 《Koillection 1.8.5 配置参数详解》第二章)。每个命令都支持一组全局选项,实测清单如下:

选项作用使用建议
-h, --help显示命令帮助了解子命令参数的第一入口
-q, --quiet只输出错误定时任务里避免日志噪声
--silent不输出任何消息同上,比 -q 更彻底
-v|-vv|-vvv提升输出详细度(1/2/3 级)排障时用 -vvv 看全栈
-n, --no-interaction不询问任何交互问题脚本/定时任务必带,交互型命令会直接放弃
-e, --env=ENV临时指定运行环境(默认 prod)调试时 -e dev
--no-debug关闭调试模式配合 -e dev 使用
--ansi|--no-ansi强制/禁用彩色输出重定向到文件时用 --no-ansi
-V, --version显示应用版本即上面的 Symfony 横幅
--profile启用性能分析(需 debug)开发环境专用

⚠️ 实测注意:doctrine 系列命令执行时首行会打印一条 User Deprecated: Doctrine\DBAL\Schema\Table::addColumn is deprecated... 的 deprecation 日志(上游 doctrine/dbal 3.7.5 与迁移库的兼容性提示,1.8.5 实测存在),它只是日志噪声,不影响命令结果,本文后续实测回显中会如实出现,请忽略。

1.2 命令全景:list

不带参数执行 bin/console list 可以列出全部可用命令(按命名空间分组):

php bin/console list

实测回显(首尾节选,完整约 130 行):

Symfony 8.0.13 (env: prod, debug: false)

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
      --silent          Do not output any message
  -q, --quiet           Only errors are displayed. All other output is suppressed
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -e, --env=ENV         The Environment name. [default: "prod"]
      --no-debug        Switch off debug mode.
      --profile         Enables profiling (requires debug).
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  about                                      Display information about the current project
  completion                                 Dump the shell completion script
  help                                       Display help for a command
  list                                       List commands
 api
  api:json-schema:generate                   Generates the JSON Schema for a resource operation.
  api:openapi:export                         Dump the Open API documentation
 app
  app:clean-up                               Delete unused images
  app:refresh-cached-values                  Refresh cached values such has counters and prices
  app:regenerate-logs                        Regenerate missing create logs
  app:regenerate-thumbnails                  Regenerate thumbnails
  app:translations:dump                      Dumps javascripts translations
 assets
  assets:install                             Install bundle's web assets under a public directory
......

(尾部还列有 cache / config / dbal / debug / doctrine / error / lexik / lint / router / secrets / security / translation 等命名空间,可用 php bin/console list 随时查看完整清单。)

对运维最有价值的三组命名空间:

命名空间代表命令用途
appclean-up / refresh-cached-values / regenerate-logs / regenerate-thumbnails / translations:dumpKoillection 自带的数据维护命令,本章第二节逐条实测
lexik / securityjwt:generate-keypair / jwt:generate-token / hash-password密钥对生成、离线签发调试令牌、密码哈希,第三、四章
doctrine / dbalmigrations:migrate / migrations:status / run-sql数据库迁移与 SQL 直查,第五章

其余命名空间(cache、debug、lint、router、secrets、translation 等)属于 Symfony 框架的通用工具,本文挑运维常用的在第五、六章演示;想看某个命令的详细参数,用 php bin/console help <命令名> 或 <命令名> --help。

1.3 about——一屏看运行环境

about 命令把框架版本、内核环境、缓存目录占用、PHP 运行时信息一屏打出来,是接手一台陌生 Koillection 服务器时应当先跑的第一条命令:

php bin/console about

实测回显:

 -------------------- --------------------------------- 
  Symfony                                               
 -------------------- --------------------------------- 
  Version              8.0.13                           
  Long-Term Support    No                               
  End of maintenance   07/2026 Expired                  
  End of life          07/2026 Expired                  
 -------------------- --------------------------------- 
  Kernel                                                
 -------------------- --------------------------------- 
  Type                 App\Kernel                       
  Environment          prod                             
  Debug                false                            
  Charset              UTF-8                            
  Cache directory      ./var/cache/prod (7.7 MiB)       
  Build directory      ./var/cache/prod (7.7 MiB)       
  Share directory      ./var/share/prod (0 B)           
  Log directory        ./var/log (13 KiB)               
 -------------------- --------------------------------- 
  PHP                                                   
 -------------------- --------------------------------- 
  Version              8.5.12                           
  Architecture         64 bits                          
  Intl locale          en_US_POSIX                      
  Timezone             UTC (2026-10-28T12:36:46+00:00)  
  OPcache              Enabled                          
  APCu                 Enabled                          
  Xdebug               Not installed                    
 -------------------- --------------------------------- 

三点解读:Symfony 8.0.13 无 LTS(维护期 2026-07 已过,这是框架常规节奏,应用层升级随上游 releases 走);目录占用给出 cache 7.7 MiB / share 0 B / log 13 KiB 的实时画像,磁盘异常增长时先看这里再进目录排查;PHP 侧确认 8.5.12、OPcache 与 APCu 已启用(性能相关)、时区为 UTC(若需改时区见配置篇第六章的 PHP 运行时参数)。

二、应用维护命令(app 命名空间)

这是 Koillection 自带的五个数据维护命令,覆盖「清理孤儿文件 → 重建缩略图 → 刷新缓存计数 → 补齐操作日志 → 导出前端翻译」五类运维场景。它们都定义在 src/Command/ 下,只操作应用自身的数据,不涉及框架内部。

2.1 app:clean-up——清理未被引用的图片

条目图片上传后会同时写数据库记录(koi_medium 表)与磁盘文件(public/uploads/<用户ID>/)。删除条目、导入中断、数据库回档都可能留下「磁盘上有、数据库里没引用」的孤儿文件。app:clean-up 用「数据库文件清单 vs 磁盘文件清单」求差集并删除差集:

php bin/console app:clean-up

实测回显(交互确认):

This action can be dangerous, please do a backup of both your database and /uploads folder. Are you sure you want to continue ? (y/N)

命令先发出危险操作警告(提示同时备份数据库与 uploads 目录),默认答案 N。输入 y 确认后继续执行:

echo y | php bin/console app:clean-up

实测回显:

This action can be dangerous, please do a backup of both your database and /uploads folder. Are you sure you want to continue ? (y/N)Getting all files paths from database...
Getting all files paths from /uploads...
Computing diff and delete unused files...
0 files deleted.
Done!

实测环境 uploads 目录与数据库完全一致(无孤儿文件),差集为空、删除 0 个文件。删除逻辑只动「数据库里没有对应记录」的文件,不会误删正常图片;但反转的风险存在——若你手工改库或回档了数据库,正常图片会被当成孤儿删掉,所以警告里强调先备份。建议把这条命令当作「手工执行、执行前备份」的季度维护项,不要挂进定时任务(原因见 2.6 节实测)。

2.2 app:regenerate-thumbnails——重建缩略图

所有图片的缩略图由 GD 库在上传时生成。更换主题、调整缩略图参数、或老版本升级后缩略图规格变化时,用这条命令按用户逐个重建:

php bin/console app:regenerate-thumbnails

实测回显(同样带危险操作确认,echo y 确认后):

This action can be dangerous, please do a backup of both your database and /uploads folder. Are you sure you want to continue ? (y/N)Regenerating thumbnails for user admin...
0 thumbnails regenerated.
Done!

输出按用户分组(实测环境只有 admin 一个用户,0 张图片所以重建 0 张)。它重建的是 koi_medium 表中已有记录的 thumbnail_path 文件,不改变数据库记录本身;确认语义与 clean-up 相同——默认 N,y 放行。

2.3 app:refresh-cached-values——刷新缓存计数

收藏集的条目数、愿望单条数、相册照片数、以及价格聚合值都做了「缓存列」加速页面渲染。手工改库、数据迁移或异常中断后这些缓存可能失真,这条命令从源数据重算一遍,全程无交互、可放心脚本化:

php bin/console app:refresh-cached-values

实测回显:

Refreshing cached values for collections...
Refreshing cached values for wishlists...
Refreshing cached values for albums...
Done!

三条 Refreshing... 分别对应收藏集、愿望单、相册三类对象的重算,末尾 Done! 收尾。这是五个 app 命令里唯一「可直接进定时任务」的数据维护命令(见 2.6 节)。

2.4 app:regenerate-logs——补齐创建日志

Koillection 会为每个对象(条目、收藏集、标签……)记录创建事件日志。通过 API 批量导入或历史数据补录时,可能缺创建日志导致时间线缺口。这条命令逐实体类型检查并补齐:

php bin/console app:regenerate-logs

实测回显:

Checking logs for App\Entity\Collection...
Checking logs for App\Entity\Item...
Checking logs for App\Entity\Wishlist...
Checking logs for App\Entity\Wish...
Checking logs for App\Entity\Album...
Checking logs for App\Entity\Photo...
Checking logs for App\Entity\Tag...
Checking logs for App\Entity\TagCategory...
Checking logs for App\Entity\Template...
Checking logs for App\Entity\ChoiceList...
Checking logs for App\Entity\Inventory...
0 logs generated.
Updating 'delete' logs...
Done!

回显把 1.8.5 会记录日志的 11 类实体全列了出来(Collection、Item、Wishlist、Wish、Album、Photo、Tag、TagCategory、Template、ChoiceList、Inventory),这段输出本身就是一张「数据对象清单」。实测环境无缺失,生成 0 条;末段 Updating 'delete' logs... 会把已删除对象的删除事件补进日志。

2.5 app:translations:dump——导出前端翻译

界面翻译存在服务端翻译文件里,而前端 JavaScript 需要一份独立 JSON。修改翻译文件或升级后,用这条命令重新导出:

php bin/console app:translations:dump

实测回显:

Dumping translations files into /opt/koillection/assets/js...
Done!

导出位置是 assets/js/(前端源码目录)。注意与构建链的关系:这份导出是 yarn build 的前置输入——改完翻译要先跑它、再构建前端(完整构建流程见 《Koillection 1.8.5 安装部署指南》第八章),只跑 dump 不重新构建的话,浏览器里看不到变化。

2.6 定时任务编排(cron)

五个维护命令里,只有 refresh-cached-values 天生适合挂 cron;其余四个要么带危险确认、要么属于构建链步骤。编排前先明确一个实测事实——确认型命令在 --no-interaction 下会静默放弃:

php bin/console app:clean-up --no-interaction

实测回显(空,退出码 0):

没有任何输出、正常退出,确认问答直接按默认值 N 放弃执行。这是好事(脚本不会误删文件),但也意味着「挂 cron 等于没跑」,所以确认型命令只能手工执行。另外提两条备选的定时机制:

💡 技术拓展:cron 与 systemd timer 是 Linux 定时任务的两大方案。 cron 配置简单(crontab -e 一行一个任务)、无状态、任何发行版都有,但日志要自己接;systemd timer 用单元文件定义,自带日志(journalctl 可查)、支持依赖编排与持久化补跑(错过的时间点开机后补执行),但配置文件更长、需要 systemd。两种方案跑的都是同一条命令,选型看个人运维习惯,小规模自托管场景 cron 更普遍。

本文实际采用 crontab,理由是单机单应用、任务少、配置一眼可读。

推荐的 crontab 编排(crontab -e 添加,以部署用户身份运行):

# 每天 03:10 刷新缓存计数(无交互,安全)
10 3 * * * cd /opt/koillection && php bin/console app:refresh-cached-values --quiet
# 每周日凌晨 04:10 备份数据库与 uploads(clean-up 与缩略图重建保持手工,不进定时任务)
10 4 * * 0 sh -c 'pg_dump -U koillection koillection > /var/backups/koillection-$(date +\%F).sql && tar czf /var/backups/koillection-uploads-$(date +\%F).tgz /opt/koillection/public/uploads'

说明:维护命令统一加 --quiet 减少邮件通知;数据库与 uploads 的定期备份排进 cron 是因为 2.1/2.2 节的危险操作都强调「先备份」——备份自动化、清理手工化,是这个组合的安全姿势。改完用 crontab -l 核对内容,无需重启任何服务。

三、JWT 密钥与令牌工具(lexik 命名空间)

Koillection 的 REST API 用 JWT 鉴权,密钥对由 lexik 包的命令生成。本章实测三个命令:生成密钥对、自检配置、离线签发令牌。参数含义(JWT_SECRET_KEY / JWT_PUBLIC_KEY / JWT_PASSPHRASE)见 《Koillection 1.8.5 配置参数详解》第四章。

3.1 lexik:jwt:generate-keypair——生成 RS256 密钥对

php bin/console lexik:jwt:generate-keypair --help

实测回显(节选关键选项):

Description:
  Generate public/private keys for use in your application.

Usage:
  lexik:jwt:generate-keypair [options]

Options:
      --dry-run         Do not update key files.
      --skip-if-exists  Do not update key files if they already exist.
      --overwrite       Overwrite key files if they already exist.

三个专属选项的用法:--skip-if-exists 用于安装脚本的幂等重放(有密钥就跳过,安装指南首次部署即用此参数);--overwrite 换钥匙(注意:旧公钥签发的所有令牌立即失效,所有已登录 API 客户端要重新拿令牌);--dry-run 只走流程不落盘。密钥落盘位置由 .env 的 JWT_SECRET_KEY / JWT_PUBLIC_KEY 决定(默认 config/jwt/private.pem 与 public.pem),私钥口令取 JWT_PASSPHRASE——生成前必须先把它填进 .env,顺序不能反(实测与排障见配置篇第四章)。

生成后用配套的自检命令验证配置闭环:

php bin/console lexik:jwt:check-config

实测回显:

The configuration seems correct.

这句 [OK] 级别的输出说明:密钥文件存在、可读、口令匹配、签名/验签通道畅通,是 JWT 链路排障的第一条命令——API 登录报 401 时先跑它再怀疑别的。

3.2 lexik:jwt:generate-token——离线签发调试令牌

写 API 对接脚本时经常需要一个测试令牌,不必走 HTTP 登录端点,直接命令行签发:

php bin/console lexik:jwt:generate-token --help

实测回显(节选参数部分):

Usage:
  lexik:jwt:generate-token [options] [--] <username>

Arguments:
  username                     Username of user to be retreived from user provider

Options:
  -t, --ttl=TTL                Ttl in seconds to be added to current time. If not provided, the ttl configured in the bundle will be used. Use 0 to generate token without exp
  -c, --user-class=USER-CLASS  Userclass is used to determine which user provider to use

实测为演示账号 admin 签发一个令牌:

php bin/console lexik:jwt:generate-token admin | head -c 120

实测回显(令牌很长,截前 120 字符):


eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3OTMxOTA5NjUsImV4cCI6MTc5MzE5NDU2NSwicm9sZXMiOlsiUk9MRV9VU0VSIiwiUk9MRV9BRE1JTiJdLCJ1c2VybmFtZSI6ImFkbWluIn0.Zfw_i2G_vAG45-QPF48tu_A-k7et212rwHkkXmUyDYLBV

令牌头部解码后是 {"typ":"JWT","alg":"RS256"},载荷含 iat/exp/roles/username,实测 iat 与 exp 相差 3600 秒(与 HTTP 登录端点签发的一致,令牌有效期 1 小时,实测过程见配置篇 4.2 节)。两个参数的进阶用法:-t 86400 签发 24 小时令牌、-t 0 签发永不过期令牌(调试用,勿用于生产);多用户提供器场景用 -c 指定用户类,Koillection 单一用户体系下不需要。命令行签发与 HTTP 端点 POST /api/authentication_token 签发的令牌完全等价,差别只是前者不需要知道密码——这正是它只应出现在服务器本机的原因。

四、密码哈希与管理员重置(security 命令 + dbal:run-sql)

忘记管理员密码、或想批量初始化用户时,Web 界面帮不上忙(它需要先登录)。这一章的闭环是:security:hash-password 生成合法哈希 → dbal:run-sql 写回数据库 → 用新密码登录验证。

4.1 security:hash-password——生成密码哈希

php bin/console security:hash-password --help

实测回显(节选,帮助文本较长):

Description:
  Hash a user password

Usage:
  security:hash-password [options] [--] [<password> [<user-class>]]

Arguments:
  password              The plain password to hash.
  user-class            The User entity class path associated with the hasher used to hash the password.

Options:
      --empty-salt      Do not generate a salt or let the hasher generate one.

实测为演示口令生成哈希:

php bin/console security:hash-password q1w2e3r4

实测回显:


Symfony Password Hash Utility
=============================

 [WARNING] Passing the password as a command argument exposes it to shell       
           history and the process list (ps, /proc/<pid>/cmdline, container     
           audit logs); prefer the interactive prompt or pass "-" to read it    
           from stdin.                                                          

 --------------- ----------------------------------------------------------------- 
  Key             Value                                                            
 --------------- ----------------------------------------------------------------- 
  Hasher used     Symfony\Component\PasswordHasher\Hasher\MigratingPasswordHasher  
  Password hash   $2y$13$AyhRFV.VNigrjQaIhjg21.PyaVajivqGgr6U3h00nFLlRMlQXlFMK     
 --------------- ----------------------------------------------------------------- 

 ! [NOTE] Self-salting hasher used: the hasher generated its own built-in salt. 

 [OK] Password hashing succeeded                                                

解读四个关键点:哈希结果 $2y$13$... 是标准 bcrypt 格式($2y$ 前缀、cost 13、22 字符盐 + 31 字符摘要,总长 60);MigratingPasswordHasher 是 Symfony 的「迁移型哈希器」,按安全配置的 auto 策略选择当前最优算法;Self-salting 说明盐内嵌在哈希串里,--empty-salt 不需要;WARNING 提示明文进命令行参数会被 shell 历史记录,交互式终端建议省略 password 参数走提示输入,脚本里用 echo "$PASSWORD" | php bin/console security:hash-password --no-interaction - 从 stdin 读(以上用法均来自命令自带帮助原文)。

💡 技术拓展:Web 应用常用的密码哈希算法有四代。 简单加盐 MD5/SHA-256 速度太快,早已不适合存密码;bcrypt(本文实测所用)基于 Blowfish,带成本因子可随硬件变慢而调高,生态最成熟;scrypt 加了内存硬度,抗 GPU 并行;argon2id 是 2015 年密码哈希竞赛冠军,内存/时间/并行三参数可调,是当前新项目的首选。Symfony 的 auto 策略会在验证时自动识别旧算法并迁移到新算法,因此库里的旧哈希能在用户下次登录时无痛升级——这也是 bcrypt 哈希依然稳居大量 PHP 应用默认位置的原因。

4.2 实战闭环:重置 admin 密码

重新提取一次哈希并赋给变量(提取正则必须用单引号包住,防止 $2y$13 被 shell 展开,教训见本节末尾排障实录):

HASH=$(php bin/console security:hash-password q1w2e3r4 2>/dev/null | grep -oE '\$2y\$13\$[A-Za-z0-9./]+' | head -1)
echo "HASH=$HASH"

实测回显:

HASH=$2y$13$ylGHxk.WJqjQoBzMfL9m/OGlGzonwzZ/2ljjURvow8bfboAmwO3au

通过 dbal:run-sql(第五章详述)写回数据库,再用 JWT 登录端点验证:

php bin/console dbal:run-sql "update koi_user set password='$HASH' where username='admin'"

实测回显:


 [OK] 1 rows affected.                                                          

回查确认写库结果(长度应为 60、前缀 $2y$13$):

php bin/console dbal:run-sql "select username, length(password) as pwd_len, left(password, 7) as pwd_head from koi_user where username='admin'"

实测回显:

 ---------- --------- ---------- 
  username   pwd_len   pwd_head  
 ---------- --------- ---------- 
  admin      60        $2y$13$   
 ---------- --------- ---------- 

最后用新密码走一次真实登录(JWT 端点无需 CSRF,最适合做验证):

curl -s -o /dev/null -w "JWT登录:%{http_code}\n" -X POST http://127.0.0.1:8143/api/authentication_token \
    -H "Content-Type: application/json" -d '{"username":"admin","password":"q1w2e3r4"}'

实测回显:

JWT登录:200

200 即密码重置闭环完成(bcrypt 带随机盐,每次生成的哈希串不同但都对应同一明文,回查与登录都是实证)。

⚠️ 排障实录:提取哈希时 $ 被 shell 吞掉,密码被更新成空串。 实测中曾把「哈希提取 + UPDATE」写成一条 shell 管道,提取正则 \$2y\$13\$... 写在双引号里,$2y、$13 被外层 shell 当作位置参数展开成了空串,正则失效导致提取结果为空,UPDATE 把 password 写成了 ''(回显同样是 [OK] 1 rows affected.,极具迷惑性):

HASH=

 [OK] 1 rows affected.

 ---------- ---------- 
  username   pwd_head  
 ---------- ---------- 
  admin                
 ---------- ---------- 

现象是随后任何登录都失败;定位靠回查 pwd_head 为空——哈希为空但 UPDATE 仍报成功。修复分两步:提取正则改放进单引号(grep -oE '\$2y\$13\$[A-Za-z0-9./]+')重新生成;写回后立刻回查 pwd_len=60,再做登录验证。教训沉淀成两条规则:bcrypt 哈希里的 $ 在任何双引号 shell 语境里都必须转义或改用单引号;UPDATE 之后必须回查行内容,不能把「1 rows affected」当作写对了的证明。

五、数据库迁移与 SQL 直查(doctrine / dbal 命名空间)

Koillection 的表结构由 Doctrine 迁移脚本管理,源码里同时带 Mysql 与 Postgresql 两套方言目录。本章实测迁移状态检查、迁移执行,并解一个实测中真实遇到的「Out-of-date! 52 migrations」之谜。

5.1 doctrine:migrations:migrate——执行迁移

先看它的完整选项:

php bin/console doctrine:migrations:migrate --help

实测回显(参数部分节选):

Usage:
  doctrine:migrations:migrate [options] [--] [<version>]

Arguments:
  version                                The version FQCN or alias (first, prev, next, latest) to migrate to. [default: "latest"]

Options:
      --write-sql[=WRITE-SQL]            The path to output the migration SQL file. Defaults to current working directory. [default: false]
      --dry-run                          Execute the migration as a dry run.
      --query-time                       Time all the queries individually.
      --allow-no-migration               Do not throw an exception if no migration is available.
      --all-or-nothing[=ALL-OR-NOTHING]  Wrap the entire migration in a transaction. [default: "notprovided"]
      --no-all-or-nothing                Disable wrapping the entire migration in a transaction.
      --configuration=CONFIGURATION      The path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
      --em=EM                            The name of the entity manager to use.
      --conn=CONN                        The name of the connection to use.

标准用法是升级到最新版(新装与升级同一命令,迁移框架保证只执行没跑过的部分):

php bin/console doctrine:migrations:migrate --no-interaction

版本参数支持 first/prev/next/latest 别名与完整类名(回滚、重放时用),--dry-run 预演不落库,--write-sql 把 SQL 导成文件供 DBA 审查。新库首装的完整执行实录(27 张表建立、68 条版本记录)见 《Koillection 1.8.5 安装部署指南》第七章。

5.2 doctrine:migrations:status——状态总览与「52 条待执行」之谜

status 是迁移体系的状态总屏:

php bin/console doctrine:migrations:status

实测回显(忽略首行 deprecation 日志噪声):

+---------------------------------------------------------------------------------------------------------------------------+
| Configuration                                                                                                             |
+----------------------+---------------------------+------------------------------------------------------------------------+
| Storage              | Type                      | Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration |
|                      | Table Name                | doctrine_migration_version                                             |
|                      | Column Name               | version                                                                |
|---------------------------------------------------------------------------------------------------------------------------|
| Database             | Driver                    | Symfony\Bridge\Doctrine\Middleware\IdleConnection\Driver               |
|                      | Name                      | koillection                                                            |
|---------------------------------------------------------------------------------------------------------------------------|
| Versions             | Previous                  | App\Migrations\Postgresql\Version20250824174425                        |
|                      | Current                   | App\Migrations\Postgresql\Version20260514195923                        |
|                      | Next                      | App\Migrations\Mysql\Version20200429093452                             |
|                      | Latest                    | App\Migrations\Postgresql\Version20260514195923                        |
|---------------------------------------------------------------------------------------------------------------------------|
| Migrations           | Executed                  | 68                                                                     |
|                      | Executed Unavailable      | 0                                                                      |
|                      | Available                 | 120                                                                    |
|                      | New                       | 52                                                                     |
|---------------------------------------------------------------------------------------------------------------------------|
| Migration Namespaces | App\Migrations\Mysql      | /opt/koillection/migrations/Mysql                                      |
|                      | App\Migrations\Postgresql | /opt/koillection/migrations/Postgresql                                 |
+---------------------------------------------------------------------------------------------------------------------------+

逐区块解读:Storage 显示已执行版本记录在 doctrine_migration_version 表(注意是单数 version,1.8.5 实测表名);Database 显示当前连接(koillection 库,驱动是 Symfony 带空闲连接管理的一层包装);Versions 里 Current 与 Latest 是同一个 PostgreSQL 迁移类,说明数据库并不落后;Migrations 的 Executed 68 / Available 120 / New 52 是理解关键——120 条可用迁移 = PostgreSQL 68 条 + MySQL 52 条,已执行的 68 条恰好是全部 PostgreSQL 迁移。

但接着跑版本检查会得到看似矛盾的输出:

php bin/console doctrine:migrations:up-to-date

实测回显:


 [ERROR] Out-of-date! 52 migrations are available to execute.                   
php bin/console doctrine:migrations:current
php bin/console doctrine:migrations:latest

实测回显(两条输出相同):

 App\Migrations\Postgresql\Version20260514195923 - [Postgresql] Add `content_type` column on `koi_scraper`.

up-to-date 说落后 52 条,current 与 latest 却指向同一个版本——谜底就在 Migration Namespaces 区块:1.8.5 源码用一套迁移类同时支持三种数据库,每个迁移类开头都带方言断言(skipIf,非本方言直接跳过)。PostgreSQL 环境下那 52 条 MySQL 迁移永远不会真正执行,但迁移框架的「可用数」统计仍把它们算作待执行。验证方法是重跑一次迁移,看这 52 条的去向:

php bin/console doctrine:migrations:migrate --no-interaction

实测回显(52 条 skip 通知,输出节选——实测首尾):

[notice] Migrating up to App\Migrations\Postgresql\Version20260514195923
[notice] Migration App\Migrations\Mysql\Version20200429093452 skipped during Execution. Reason: "Mysql or Mariadb migration only. Skipped."
[notice] Migration App\Migrations\Mysql\Version20200727114843 skipped during Execution. Reason: "Mysql or Mariadb migration only. Skipped."
[notice] Migration App\Migrations\Mysql\Version20200812160901 skipped during Execution. Reason: "Mysql or Mariadb migration only. Skipped."
......
[notice] Migration App\Migrations\Mysql\Version20260514194959 skipped during Execution. Reason: "Mysql or Mariadb migration only. Skipped."
[notice] finished in 7.8ms, used 16M memory, 52 migrations executed, 0 sql queries

 [OK] Successfully migrated to version:                                         
      App\Migrations\Postgresql\Version20260514195923                           

52 条全部以 [notice] ... skipped during Execution. Reason: "Mysql or Mariadb migration only. Skipped." 跳过,总结行 52 migrations executed, 0 sql queries 说明一条 SQL 都没碰数据库,7.8 毫秒结束。结论:PostgreSQL 环境下 up-to-date 报 52 条待执行属预期现象,不是故障;判断数据库是否落后,看 current 与 latest 是否一致即可。up-to-date 的真实用途是在 MySQL/MariaDB 部署里当终态断言(那边所有 120 条要么执行要么跳过,最后返回 [OK] Up-to-date!)。

5.3 dbal:run-sql——不进数据库客户端直查 SQL

日常巡检、重置字段、快速核对数据,不必切到 psql 客户端再输一遍口令——dbal:run-sql 直接复用应用 .env 里的数据库凭据:

php bin/console dbal:run-sql "select count(*) from koi_item"

实测回显:

 ------- 
  count  
 ------- 
  0      
 ------- 

自带表格化输出,任何一句 SQL 都能这样跑(4.2 节的密码重置 UPDATE、回查 SELECT 都是它的真实用例)。需要注意它执行的是当前 .env 所指数据库的凭据,多实例运维时先 grep "^DB_" .env 确认连的是哪个库再动手,避免在错误实例上执行 UPDATE。

六、路由与缓存调试(debug / cache 命名空间)

Symfony 的 debug 命令族把框架内部结构摊开给你看。运维最常用的两条:查路由表(确认 URL 归属、排查 404)与清缓存(配置生效的第一动作)。

6.1 debug:router——路由全表

php bin/console debug:router

实测回显(完整输出约 280 行,节选两段——实测首尾):

 --------------------------------------------------- ---------- ---------------------------------------------------------- 
  Name                                                Method     Path                                                      
 --------------------------------------------------- ---------- ---------------------------------------------------------- 
  api_doc                                             GET|HEAD   /api/docs.{_format}                                       
  api_genid                                           GET|HEAD   /api/.well-known/genid/{id}                               
  api_validation_errors                               GET|HEAD   /api/validation_errors/{id}                               
  api_entrypoint                                      GET|HEAD   /api/{index}.{_format}                                    
......
  app_admin_index                                     GET        /admin                                                    
  app_admin_export_images                             GET        /admin/export/images                                      
  app_admin_refresh_caches                            GET        /admin/refresh-caches                                     
  app_admin_configuration_index                       GET|POST   /admin/configuration                                      
  app_admin_error_index                               GET        /admin/errors                                             
  app_admin_error_show                                GET        /admin/errors/{id}                                        
  app_admin_user_index                                GET        /admin/users                                              
  app_admin_user_add                                  GET|POST   /admin/users/add                                          
  app_admin_user_edit                                 GET|POST   /admin/users/{id}/edit                                    
  app_admin_user_delete                               POST       /admin/users/{id}/delete                                  

路由命名一眼可辨:api_ 开头的是 API Platform 自动生成的 REST 接口(占大头),_api_ 开头是它的内部辅助路由,app_ 开头是手写控制器定义的 Web 页面路由(上节选的管理后台组:管理员面板、图片导出、缓存刷新、配置页、用户管理)。遇到 404 时先在这里确认「路由到底存不存在、方法对不对」,比翻源码快得多。

想知道某个 URL 到底命中哪条路由,用 router:match 模拟匹配——以登录页 POST / 为例(登录路由就是根路径,实测):

php bin/console router:match --method=POST /

实测回显:

| Path         | /                                                       |
| Path Regex   | {^/$}sDu                                                |
| Host         | ANY                                                     |
| Host Regex   |                                                         |
| Scheme       | ANY                                                     |
| Method       | GET|POST                                                |
| Requirements | _locale: en|fr|es|de|it|nl|pl|pt|pt_BR|ru|zh            |
| Class        | Symfony\Component\Routing\Route                         |
| Defaults     | _controller: App\Controller\SecurityController::login() |
| Options      | compiler_class: Symfony\Component\Routing\RouteCompiler |
|              | utf8: true                                              |

命中 app_security_login → SecurityController::login(),同时能看到这条路由对 _locale 有白名单要求(en/fr/es/de/it/nl/pl/pt/pt_BR/ru/zh,即 1.8.5 官方支持的语言集)。

6.2 cache:clear 与 cache:pool:list——缓存层操作

改完 .env、翻译文件或任何配置后,重建应用缓存使其生效:

php bin/console cache:clear

实测回显:

 [OK] Cache for the "prod" environment (debug=false) was successfully cleared.

prod 环境的缓存是编译产物(var/cache/prod,约 7.7 MiB,见 1.3 节 about),清除后会自动重建。Symfony 把不同用途的缓存拆成独立的池,改了某类数据可以只清对应池,先看有哪些池:

php bin/console cache:pool:list

实测回显:

 ------------------------------------------------------------------ 
  Pool name                                                         
 ------------------------------------------------------------------ 
  cache.app                                                         
  cache.system                                                      
  cache.validator                                                   
  cache.serializer                                                  
  cache.property_info                                               
  cache.http_client.pool                                            
  doctrine.result_cache_pool                                        
  doctrine.system_cache_pool                                        
  cache.property_access                                             
  cache.validator_expression_language                               
  cache.security_expression_language                                
  cache.security_is_granted_attribute_expression_language           
  cache.security_is_csrf_token_valid_attribute_expression_language  
  cache.security_token_verifier                                     
  cache.reprise                                                     
  api_platform.cache.route_name_resolver                            
  api_platform.cache.metadata.resource                              
  api_platform.cache.metadata.property                              
  api_platform.cache.metadata.resource_collection                   
  api_platform.cache.metadata.operation                             
  api_platform.cache.openapi                                        
 ------------------------------------------------------------------ 

实测 21 个池,覆盖应用、校验、序列化、安全表达式、Doctrine 结果集与 API Platform 元数据等。日常运维记住一个原则:拿不准就整体 cache:clear(副作用只是下次请求慢一点),cache:pool:clear <池名> 属于精细操作,排障定位到具体池时再用。

七、命令速查表

全篇实测命令的速查汇总(命令均以 cd /opt/koillection 后执行为前提):

命令用途交互确认建议频率备注
php bin/console about一屏查看运行环境与目录占用无接手/巡检时版本、env、cache/log 占用
php bin/console app:refresh-cached-values重算收藏集/愿望单/相册缓存计数无每日 cron五个 app 命令中唯一适合自动化
php bin/console app:clean-up清理无引用的孤儿图片y/N季度手工先备份数据库与 uploads;--no-interaction 会静默放弃
php bin/console app:regenerate-thumbnails按用户重建全部缩略图y/N需要时手工同样先备份
php bin/console app:regenerate-logs补齐缺失的创建/删除日志无批量导入后回显含 11 类实体清单
php bin/console app:translations:dump导出前端 JS 翻译文件无改翻译/升级后之后需 yarn build 才生效
php bin/console lexik:jwt:generate-keypair --skip-if-exists生成 RS256 密钥对无首装一次--overwrite 换钥匙会使全部令牌失效
php bin/console lexik:jwt:check-configJWT 链路自检无API 报 401 时The configuration seems correct.
php bin/console lexik:jwt:generate-token <用户名>离线签发调试令牌无联调时-t 0 永不过期,勿用于生产
php bin/console security:hash-password生成 bcrypt 密码哈希可选重置密码时交互输入或 stdin 传明文更安全
php bin/console dbal:run-sql "<SQL>"复用 .env 凭据直查/修数无巡检/修数UPDATE 后必须回查
php bin/console doctrine:migrations:migrate --no-interaction升级表结构到最新无(加 -n)每次升级后PG 环境会跳过 52 条 MySQL 迁移,属预期
php bin/console doctrine:migrations:status迁移状态总览无升级前后Executed/Available/New 三数对照
php bin/console doctrine:migrations:current / latest判断库是否落后无升级前后两者一致即最新,别信 New 计数
php bin/console debug:router查看全部路由无排查 404实测约 280 行,app_ 前缀为 Web 路由
php bin/console router:match --method=GET <路径>模拟路由匹配无排查 404显示命中的控制器
php bin/console cache:clear重建应用缓存无改配置后prod 缓存自动重建
php bin/console lint:yaml config校验 YAML 语法无改配置文件后实测 22 个文件全部合法

定时任务最小集(详细编排见 2.6 节):app:refresh-cached-values 每日一次 + 数据库/uploads 备份每周一次,其余命令全部手工执行。

参考链接

  1. 官方命令速查(1.8.5 仓库 cheatsheet.md):https://github.com/koillection/koillection/blob/1.8.5/cheatsheet.md
  2. Symfony Console 文档(入口与全局选项):https://symfony.com/doc/current/console.html
  3. Doctrine Migrations 文档(迁移选项与状态语义):https://www.doctrine-project.org/projects/doctrine-migrations/en/3.x/index.html
  4. Lexik JWT Authentication Bundle 文档(密钥对与令牌):https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md
  5. 站内延伸:《Koillection 1.8.5 介绍与选型指南》、《Koillection 1.8.5 安装部署指南》、《Koillection 1.8.5 配置参数详解》