关于 basercms4-to-5-upgrade
面向 AI Agent 的 baserCMS 4 到 5 迁移技能,覆盖环境确认、插件与主题盘点、数据库迁移及逐步测试。它强调按检查清单执行顺序,并将跨文件问题统一排查和验证。
主要功能
- 01提供分阶段迁移检查清单
- 02指导环境与迁移对象确认
- 03覆盖数据库、插件和主题迁移
- 04要求跨文件排查并批量修复
- 05包含语法、测试与浏览器验证
适用场景
- 01规划 baserCMS 4 项目升级到 5
- 02盘点并决定插件和主题的迁移方式
- 03迁移数据库及上传文件
- 04按顺序验证主题和插件运行状况
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ baserproject/ baser-skills --skill basercms4-to-5-upgrade安装后在 Claude Code 中输入/basercms4-to-5-upgrade确认已加载。
详细介绍
baserCMS 4 から 5 へのアップグレード/移行ルール
このファイルは、baserCMS 4 (CakePHP 2ベース) のコードを baserCMS 5 (CakePHP 5ベース) に移行する際、AIエージェントが遵守すべきルールとパターンを定義します。
推奨: 移行に着手する前に一度
basercms5-claude-workflow-setup(環境セットアップ)を参照し、進め方の環境(権限整理=permissions-audit/その上での Auto mode/設計=superpowers brainstorming/spec・plan の Markdown プレビュー)を整える。提案ベースで、整っていればスキップ。
基本方針
- フレームワークの差異: baserCMS 4 は CakePHP 2、baserCMS 5 は CakePHP 5 ベースです。CakePHP 2 の記法は基本的に動作しません。CakePHP 5 の記法に完全に書き換えてください。
- クラスの置換: 廃止されたクラスは、代替クラスまたはPHP標準クラスに置き換えてください。
- アクセサの利用: プロパティへの直接アクセスは避け、Getter/Setter を使用してください。
- アップグレードの詳細情報については https://baserproject.github.io/5/ver5_migration を参考にする。
- 【最重要・横断対応の原則】1画面の修正で見つけた不具合のうち、同じ原因がプラグイン/サイト全体に散在するものは、その場で“横断的に”一括対応する。1箇所だけ直して次の画面で同じエラーに当たる、を繰り返さない。手順: ①エラーを直したら 同じパターンを
grep -rnで全件洗い出す(例:$this->Form->input(、'multiple' => 'checkbox'、単数get('Sample.Sample...')、searches/、Time->format($x)第2引数なし 等)→ ②機械的に一意な変換はperl -piで一括適用 → ③変更ファイルを全てphp -lで検証 → ④非自明な箇所だけ個別対応。横断一括できる代表例は basercms-plugin-4-to-5-upgrade スキルの C-0(機械的に一括変換できるパターン) にカタログ化してある(見つけ次第追記する)。新しい横断パターンを見つけたらまず C-0 に追加してから一括実行する。プラグイン内部コード(Controller/Table/Entity/View/Helper/フォーム/Vue・JS)の具体的な書き換えは同スキルを参照。
標準移行フロー(この順で進める・正本)
移行全体はこのチェックリストの順序で進める。順序依存の罠(★印)が複数あるため、節の並びや思い込みで順番を変えないこと。各工程の詳細は参照先の節に書いてある。
- 0. 実行環境の確認 — Docker利用有無・コンテナ名・PHPバージョン・プロキシ構成をユーザーに確認 → 「前提: 実行環境の確認」節
- 1. 4系の現状調査 — プラグイン一覧(
app/Plugin/)・テーマ(theme/)・DB名/プレフィックス・マルチサイト有無・サブモジュール有無(find app/Plugin theme -name .git)・管理プレフィックス(app/Config/core.phpのRouting.prefixes)を洗い出す - 2. 移行対象の確定(棚卸し) — プラグイン・テーマを1つずつ (a)既存5系版利用/(b)4系を変換/(c)廃止 に分類し、表でユーザーの合意を取る → 「プラグイン棚卸し」節
- 3. 移行計画の作成 — 棚卸し結果を反映した計画を作成しユーザー承認(進め方の環境は
basercms5-claude-workflow-setup参照) - 4. トピックブランチ作成 — 移行作業用ブランチを切る(例
git switch -c basercms5-migration)。v5 配置物の git 取り込み時の注意は「Git / リポジトリ運用」節(G-1〜G-4) - 5. 4系バックアップ作成 — v4 管理画面「データメンテナンス」で作成 → zip を
v5/tmp/へ。★PHP切替(7.4→8.1)を伴う環境では、v5 インストール=PHP を上げる【前】に必ず取る(上げた後だと v4 管理が不調になり得る)→ 「データベース移行手順」節 1. - 6. 5系を
/v5/にインストール — パッケージ取得 → composer → .env →bin/cake install→ 実ブラウザでログイン確認 → 「baserCMSの最新版の取得」〜「baserCMSのインストール」節 - 7. BcDbMigrator 導入 → DB変換 — 変換zipの出力まで。★復元はまだしない(工程12まで待つ)→ 「データベース移行手順」節 2.-3.
- 8. BcAddonMigrator 導入 — 「テーマの変換」節 2.
- 9. (a)既存5系版の導入 + (b)テーマ・プラグインの変換・配置 — (b) は zip 化 →
bc_addon_migrator→v5/plugins/展開。★(a) の導入もここ(復元前)で行う。終盤に回すとそのプラグインのテーブルにデータが復元されない → 「テーマの変換」「プラグインの変換」節 - 10. プラグインを DB で直接有効化 —
pluginsテーブル INSERT(Migrations を持つものはmigrations migrate -p併走)。★有効化で boot 経路の4系残骸が fatal 化するので、bin/cake versionスモークが通るまで最小修正。検証は CLI+SQL まで(ブラウザ確認はまだしない — 画面は工程15-17の5系化まで出なくて正常)→ 「プラグインの有効化(DB直接・標準)」節 - 11. テーマを DB で直接適用 —
sites.themeUPDATE + キャッシュ全消去 → 「テーマの適用(DB直接)」節 - 12. DB復元 — v5 管理画面「データメンテナンス」で変換済み zip をブラウザ復元(復元CLIなし・ユーザー実施)。★必ず工程10-11(有効化・適用)の後。直前に管理画面ログインの生存だけ確認(フロントは見ない)。復元後にテーブル生成・件数を SQL で検証 → 「データベース移行手順」節 4.
- 13. アップロードファイルの移行 —
/files→/v5/webroot/files→ 「アップロードファイルの移行」節 - 14. 移行台帳(ファイル一覧)の作成 — 対象プラグイン・テーマごとに構成ファイル一覧と状態を記した台帳を
docs/superpowers/に作る(.superpowers/はSDD内部スクラッチなので置かない)。以降の横断チェック・動作確認の進捗と懸案はすべてここに記録する。状態の語彙は「未着手/修正済み/非該当(理由付き)」を必ず区別する — 横断チェックで grep にヒットしなかったファイルは「未着手」ではなく「非該当(既知パターンhitなし・最終検証は工程17の描画確認)」。集計表の「完了」は「既知パターンの横断適用が完了」の意味であり全ファイル個別検査済みではない、と台帳に明記する(誤解の実例あり) - 15. テーマの横断チェック → 5系化(下ごしらえまで) — TH-系パターン(
siteConfig[]廃止・fullUrl()廃止 等)を grep で全件洗い出して一括対応 →basercms-theme-4-to-5-upgradeスキル(TH-系+テンプレート・テーマ描画系の F-系)。完了基準は php -l 全通過まで。描画確認はここではしない(工程17の最初にユーザーと行う)。テンプレのビュー変数は事前の全量マッピングをせず、grep で見つかる「4系特有で5系コアが供給しない変数($siteConfig等)」だけ先に書き換え、コア供給分は工程17の実描画+ログ検出に任せる - 16. プラグインの横断チェック → 5系化(下ごしらえまで) — C-0(機械一括変換カタログ)を先に全プラグインへ適用 → T-/C-系を個別対応。完了基準は php -l 全通過まで。無理な改善(動くものの過剰リファクタ)はせず、気づきは台帳にメモして先へ進む →
basercms-plugin-4-to-5-upgradeスキル - 17. テーマ→プラグインの順に1つずつ動作確認(ユーザー協働) — ★開始前に移行対象プラグインを一旦全部無効化し(
UPDATE plugins SET status=0 WHERE name IN (...)+キャッシュクリア)、まず「テーマのみ有効」の素の状態でフロント描画をユーザーと確認(レイアウト→トップ→一覧→詳細の画面単位。500 はerror.log、穴あき描画はgrep "Undefined variable"で機械検出し、警告ゼロまで直す)。その後、確認対象プラグインを1つずつ有効化しながら進める。イベントリスナー等で他プラグインの影響を受けやすく、全部有効のままだと不具合の切り分けができないため。対象が他プラグインに依存する場合はその依存プラグインだけを併せて有効化する。プラグインごとに次の順で:- a. コントローラ/テンプレート以外(Table/保存/集計)をユニットテストで確認(依存が重いものはスキップ可・台帳にメモ)→
basercms-unittestスキル - b. コントローラの統合テストを作成して実行(この時点の失敗は許容して台帳に記録)。★スタンドアロンUT基盤が入っているプラグインでは b をブラウザ確認より先に回すと費用対効果が高い(実証済み): GET描画テストが「setting.php の snake_case 由来の全管理画面404」や「control() 自動id とインラインJSセレクタの不一致(C-F2)」をブラウザ往復ゼロで検出した。基盤未導入のプラグインまで b のために基盤導入するかは、画面数とロジック量で判断(イベントグルー中心の小型はブラウザ確認で足りる)
- c. ユーザーにブラウザ動作確認を依頼(URLはリンク付きで提示)→ エラーはスクリーンショット/文言をもらって解決
- d. b. で失敗していたコントローラテストを解決(緑化)
- e. 対象の確認が終わったら有効のまま次のプラグインへ(最終的に全対象が有効・全確認済みになる)
- a. コントローラ/テンプレート以外(Table/保存/集計)をユニットテストで確認(依存が重いものはスキップ可・台帳にメモ)→
- 18. 懸案プラグインの方針決定・対応 — 棚卸しで「要確認」だったもの・台帳の懸案メモを、ユーザーと方針決定(対応/延期/廃止)して消化する
- 19. 最終統合テスト — ユーザーが実ブラウザでフロント・管理・フォーム・ブログを通し確認。問題があれば解決
- 20. Git 取り込み → 完了 — G-1〜G-4 の確認をして v5 をコミット → 「Git / リポジトリ運用」節
<analysis 3="">## 前提:确认运行环境(必须首先进行)
在开始迁移的具体工作(获取软件包、composer、bin/cake install、数据库迁移、工具转换)之前,必须先向用户确认运行环境。不要通过推测或探索(如 docker inspect 等)来猜测。
- 询问是否使用 Docker,以及容器名称是什么(最重要):本技能的命令示例中经常使用
docker exec <container-name> ...,但容器名称因环境而异。必须首先询问:“您是否在使用 Docker?如果是,请告知容器名称。” 在通过docker ps或docker inspect猜测之前,先询问用户(许多情况下,Compose 定义不在仓库中,而是在另一个仓库中;探索可能导致误判或绕远路)。同时确认数据库容器名称、数据库用户名/密码、VIRTUAL_HOST等信息。 - 确认现有容器的 PHP 版本(baserCMS 5 必须使用 PHP 8.1+):baserCMS 4 通常运行于 php7.4 等版本,但 baserCMS 5 必须使用 PHP 8.1 或更高版本。如果要让 v5 与现有容器共存,而容器中的 PHP 低于 8.1(例如
baserproject/basercms:php7.4),则 必须将 image 升级到 php8.1 或更高版本(修改 compose 中的 image 标签 → 重启)。image 的修改通常需要编辑 Compose 定义(有时位于另一个仓库),因此,请先确认编辑位置;如果位于仓库之外,请让用户执行修改,或先取得明确授权再进行。- ★升级 image 前,必须警告并确认“v4 可能无法继续运行”:升级到 PHP 8.1 后,同一容器中的 v4 也会在 8.1 上运行,v4 可能无法正常运行。执行切换前,必须明确询问:“我将把容器改为 8.1,但 v4 可能无法继续运行。这样可以吗?”,取得同意后再进行修改。应先取得同意,而不是事后再检查 v4 是否运行(因为 v4 迟早会废弃,切换后无需确认 v4 是否运行)。
- 将 v5 构建为“现有容器和现有挂载中的子目录”(不要新建其他容器/虚拟主机):在项目根目录下创建
v5文件夹,并通过现有容器的挂载,将其作为/var/www/html/v5在同一容器中提供服务。因此,登录 URL 会是https://<既存ホスト>/v5/baser/admin/...。不要为了并行运行而过度设计、增加其他服务(v4 保持原样,不停机)。
沟通与语言(重要)
所有沟通和创建的文档都必须使用日语。
具体而言,以下内容必须使用日语编写:
- 聊天回复:发送给用户的消息、进度报告、问题。
- Task Artifact(task.md):进度管理清单、任务名称、摘要。
- Implementation Plan Artifact:实现计划详情、目标、变更内容、验证计划。
- Walkthrough Artifact:工作回顾、验证结果报告。
[重要・URL 必须以链接形式提供] 当请用户通过浏览器确认运行情况时(管理后台登录 URL、数据维护页面、前台确认等),必须将 URL 显示为 Markdown 链接([https://...](https://...))。不要以纯文本 URL 显示(方便用户点击并立即打开)。示例:👉 [https://<project>.localhost/v5/baser/admin/baser-core/users/login](https://<project>.localhost/v5/baser/admin/baser-core/users/login)。
[重要・每次询问用户时都必须使用 AskUserQuestion(选择式下拉菜单)] 在等待用户回复时,例如确认方针、选择 A/B、确认用户是否已完成所请求的操作,不要只在正文中提问,必须使用 AskUserQuestion 工具。显示下拉菜单后,用户的手机会收到通知;只用文本提问则不会收到通知,用户可能注意不到。迁移工作耗时很长,用户经常会离开座位,因此是否收到通知会显著影响往返沟通的响应时间(这是根据用户要求和实际运用确立的做法)。即使选项不合适,也可以选择“其他”并自由输入,所以有疑问时就使用下拉菜单。
获取 baserCMS 最新版
从 GitHub clone 的代码是开发版,不会用于实际项目。 请使用以下 URL 获取打包后的代码。 https://basercms.net/packages/download_exec/basercms-x.x.x.zip
请在项目中创建名为 v5 的文件夹,并将获取的代码放入其中。
获取方式(主机的 curl/wget 被 deny 时的备用方法):download_exec URL 是供浏览器使用的生成式下载链接,而 WebFetch 是用于将网页转换为 Markdown 并进行摘要的工具,因此无法保存 zip 等二进制文件。主机上的 curl/wget 也经常因权限而被 deny。这种情况下,如果使用 Docker,可以“通过容器”获取(只要 Bash(docker:*) 已获许可,docker exec ... curl 就不会被 Bash(curl:*) 的 deny 规则拦截)。项目已挂载到容器中,因此在容器内下载后,主机端也能看到文件。请通过 GitHub Releases(baserproject/basercms 的 latest)确认最新稳定版的版本。
# 例: コンテナ内でパッケージを取得(マウント先 /var/www/html にプロジェクトがある想定)
docker exec -w /var/www/html <container> bash -lc \
'curl -fL -A "Mozilla/5.0" -o basercms-<x.x.x>.zip "https://basercms.net/packages/download_exec/basercms-<x.x.x>.zip"'
# 取得後: file / unzip -l で zip 妥当性を確認 → unzip -q -o basercms-<x.x.x>.zip -d v5/
只有在难以通过容器获取时,才请用户通过浏览器下载并告知文件路径。
使用 composer 安装软件包
运行 composer install。
-
软件包版的
vendor/为空(仅有.gitkeep),因此必须运行composer install。解压后即使test -d vendor返回真,目录中也可能没有内容(因为仅有.gitkeep,所以目录存在)。请通过检查vendor/autoload.php是否存在来判断;如果不存在,则运行composer install。 -
4 系插件使用的第三方软件包需要在 v5 中通过
composer require显式安装:源自 4 系composer.json的库(例如phpoffice/phpspreadsheet)可能未包含在 v5 的composer.json/vendor 中,导致出现Class "PhpOffice\PhpSpreadsheet\Reader\Xlsx" not found等错误。请参考 4 系的composer.json,安装与 PHP 版本(v5 为 8.1+)兼容的版本(例如docker exec -w <v5> <container> composer require "phpoffice/phpspreadsheet:^1.29"→ 会安装 1.30.x)。执行后使用php -r 'class_exists(...)'确认问题已解决。 -
Excel/PDF 等模板资源(.xlsx 等)已迁移至
templates/Admin/Excel/...,路径结构与 4 系的View/Excel/admin/...不同:如果生成类组件(如 SampleExcel)仍按 4 系布局构造Plugin::templatePath('Sample') . 'Excel' . DS . 'admin' . DS . ...,就会出现File "..." does not exist。还要注意,templatePath()末尾带斜杠,因此再添加. DS .会产生//。请改为 v5 的实际路径Plugin::templatePath('Sample') . 'Admin' . DS . 'Excel' . DS . <controller> . DS . <file>.xlsx(使用find <plugin> -iname "*.xlsx"确认实际文件位置)。
复制 .env 文件
将 v5 文件夹内的 /config/.env.example 复制为 /config/.env。
将 HASH_TYPE 设置为 sha1。
★务必将 SECURITY_SALT 设置为与 v4 的 Security.salt 相同的值(从 app/Config/core.php 中的 Configure::write('Security.salt', '...') 转录。.env 中对应行默认被注释,请取消注释)。4 系的密码使用 sha1(salt.password),因此,如果 salt 不一致,恢复数据库后将无法使用任何 v4 用户登录(我们实际遇到过这个问题。.env 的注释中也明确写着“设置 4 系使用的安全盐值”。)。
此外,如果使用 nginx-proxy 容器,请将 .env 中 TRUST_PROXY 的值设为 true。
安装 baserCMS
创建一个用于 v5 的新数据库,并在 v5 文件夹内运行安装命令。
# 引数の並び: <設置URL> <管理者メール> <管理者パスワード> <データベース名>
# ★第4引数がDB名。--database というオプションは存在せず、付けると `Unknown option `database`` で失敗する
# ★サブディレクトリ設置では --baseurl も付ける
bin/cake install [設置URL(例:https://localhost/v5/)] [管理者メール] [管理者パスワード] [DB名(例 <既存DB>_v5)] \
--baseurl [/v5/] --host [DBホスト名] --username [DBユーザー名] --password [DBパスワード]
- 数据库名称是第 4 个位置参数(没有
--database选项)。创建一个在现有数据库名称后添加_v5后缀的数据库,然后传入该名称。 - 安装在子目录时,请添加
--baseurl /v5/。
.htaccess 的 RewriteBase 大多数情况下无需修改即可正常工作(v5 默认的 .htaccess 使用相对重写,因此通常无需调整即可在 /v5/ 子目录下运行=已验证)。仅在出现 /v5/v5 重复(404)或重定向循环时,才调整 webroot/.htaccess 中的 RewriteBase(首先检查下方的 SITE_URL 和残留缓存)。
登录 URL 的形式如下:https://localhost/v5/baser/admin/baser-core/users/login。
- [重要・安装在子目录时,SITE_URL 必须包含子目录+修改后务必清除所有缓存] 安装在子目录时,
config/.env中的SITE_URL应为包含子目录的完整 URL(例如https://localhost/v5/)。不要将其改为域名根路径(https://localhost/)——虽然看起来/v5/v5的重复问题消失了,但反而会导致管理登录不断向自身发送 302,陷入无限循环(因为 loginUrl 与请求路径不一致,登录页面会被误判为“受保护对象”)。- 管理界面出现
/v5/v5重复(404)或重定向循环时,真正原因往往是“修改.env(尤其是 SITE_URL)后的残留缓存”。baserCMS 会缓存根路径/URL,因此修改.env后务必运行bin/cake cache clear_all。将 SITE_URL 恢复为正确的https://host/v5/并清除缓存即可解决(已验证)。 - [请通过真实浏览器验证,而非在容器内使用 curl] 在
nginx-proxy代理下,即使在容器内运行curl https://localhost/...,请求也不会携带X-Forwarded-Proto等代理标头,因此重定向行为会与真实浏览器不同(SSL/规范化重定向的判定会出现偏差)。务必通过代理访问的真实浏览器确认管理界面的重定向是否正常。不要轻信容器内 curl 返回的 302/重复路径,并误判为“子目录的根本缺陷”。
- 管理界面出现
数据库迁移步骤
请推荐并指导用户使用专用插件 BcDbMigrator 执行数据库迁移,而不是直接改写 SQL。
该插件不提供命令,必须通过浏览器使用。
-
前提条件:
- 迁移源:baserCMS 4.5.5 以上。
- 迁移目标:已全新安装 baserCMS 5。
-
移行フロー(DB移行は「①バックアップ→②変換」と「③復元」に分かれる。②までは早期に実施できるが、③復元は必要なv5プラグインを導入した後=プラグイン棚卸し/変換フェーズの後に行う):
- バックアップ (v4): baserCMS 4 管理画面「データメンテナンス」でバックアップを作成し、ダウンロードした zip を
/v5/tmp/に配置してもらう。- [重要・PHPバージョンとの順序] v4 バックアップ作成には v4 管理画面が動く PHP が要る。v5 のために先にコンテナを PHP 8.1 へ上げると、サポート外の v4 管理が不調になり得る。バックアップは PHP を上げる前に取るか、既に上げてしまったら一時的に v4 サポート版(例 php7.4)へ戻してバックアップを取り、再度 8.1 へ戻す(v4 と v5 は必要 PHP が違うため同時稼働はできない)。
- [重要・v4 管理URLは決め打ちしない] 管理ログインが
/adminで 404 になるサイトは管理プレフィックスを変更している(app/Config/core.phpのConfigure::write('Routing.prefixes', ...)。例cmsadmin→/cmsadmin/users/login、データメンテナンスは/cmsadmin/tools/maintenance)。404 を安易に「PHP切替で壊れた」と誤診しない——まずRouting.prefixesを確認する。
- ツール準備 (v5):
BcDbMigratorを配置する。取得は composer でも GitHub でも可(旧記載の「composer 不可」「plugins/ 必須」は誤り=composer 取得可・vendor 配下でも baserCMS は認識する):- (a) composer: packagist に
baserproject/bc-db-migratorが公開されておりcomposer require baserproject/bc-db-migrator:^5.2で取得できる。ただしこのパッケージのcomposer.jsonに autoload 定義が無いため、cakephp plugin-installer がUnable to get primary namespaceでconfig/plugins.phpへの自動登録に失敗する(=ダウンロード自体は成功)。確実に使うなら、取得済みファイルをplugins/BcDbMigratorにコピーして下記の DB 有効化を行う(composer からはcomposer removeして composer.json をクリーンに保つとよい)。 - (b) GitHub:
git clone --branch 5.2.0 https://github.com/baserproject/BcDbMigrator.git plugins/BcDbMigrator(clone 後.gitを除去してサブモジュール化を回避)。※Auto mode では外部リポジトリ取得が分類器にブロックされることがあるので、ユーザーに取得元を提示して承認を得る。 有効化は2通り: - (推奨・低摩擦) DB レコードで有効化:
BcDbMigratorはインストールスクリプト(マイグレーション)を持たないため、pluginsテーブルに1行 INSERT すれば有効化できる(name='BcDbMigrator', title='BcDbMigrator', version='5.2.0', status=1, db_init=1, priority=<末尾+1>, created/modified=NOW())。ブラウザ操作不要。有効化後bin/cakeにコマンドが出る。 - (代替) 管理画面のプラグイン管理からインストール。※
cake plugin load/config/plugins.php直接編集は不可(ルーティング不整合でクラッシュ要因)。
- (a) composer: packagist に
- 変換実行(CLI 対応・5.2.0 以降): BcDbMigrator 5.2.0 で CLI 実行に対応した(旧版はブラウザ専用)。
docker exec <container> bash -lc 'cd v5 && bin/cake bc_db_migrator tmp/<v4バックアップ>.zip'を実行すると、変換済み zip がv5/tmp/baserbackup_<v5version>_<日時>.zipに出力される(アップロード/ダウンロードの往復が不要。エラー時もアシスタントが反復できる)。変換は一時接続(bcOldDbMigrator/bcNewDbMigrator・接頭辞付き一時テーブル)で行われライブ DB は変更しない(出力は zip のみ)。- [重要・baser-core 5.2.5 との非互換パッチ] BcDbMigrator 5.2.0 の変換は旧スキーマPHPを
extends \BaserCore\Database\Schema\BcSchema(FQN)に置換するが、baser-core 5.2.5 のBcDatabaseService::isValidSchemaFile()は AST で extends が短縮名BcSchemaの完全一致であることを要求するため、無効なスキーマファイル: BcSchema を継承し、drop/create メソッドをオーバーライドしてはいけませんで全滅する(CLI/ブラウザ共通の Component 経路)。対処:plugins/BcDbMigrator/src/Controller/Component/BcDbMigratorComponent.phpの_createTableBySchema()内、extends CakeSchemaを FQN でなく短縮名に置換しuse文を足す:
(本家 BcDbMigrator 未対応のためのローカルパッチ。根本原因は baser-core 側=$contents = preg_replace('/extends CakeSchema/', 'extends BcSchema', $contents); $contents = str_replace('<?php', "<?php\nuse BaserCore\\Database\\Schema\\BcSchema;", $contents);isValidSchemaFile()が短縮名の完全一致のみ許可し FQN を弾く点。これを FQN も受理するよう緩和する修正を baserproject/basercms へ PR #4438(5.3.x 宛)で提出済み。マージ・リリースまでは本ローカルパッチ(BcDbMigrator 側で短縮名に置換)が必要。5.3 以降ではパッチ不要になる見込み。)
- [重要・baser-core 5.2.5 との非互換パッチ] BcDbMigrator 5.2.0 の変換は旧スキーマPHPを
- 復元 (v5): baserCMS 5 管理画面「データメンテナンス」で変換後 zip を復元(復元CLIは無くブラウザ専用)。この工程はプラグイン棚卸し/変換の後に行う(下記「プラグイン」注意点)。
- 復元は zip の中身基準で動く(実装確認済み):
UtilitiesService::_loadBackup()は zip 内の全*Schema.phpを drop→create し全 CSV を投入するだけで、pluginsテーブルの有効/無効は参照しない。したがって、変換済み zip にスキーマ+CSV が入っているテーブルは、該当プラグインが無効でも取り込まれる(unzip -lで<Table>Schema.phpの同梱を確認しておく)。 - ★復元は
pluginsテーブル自体も zip の内容(=v4 のプラグイン一覧・全行 status=0)で置き換える(実測): 復元前に行った有効化レコード(コアの BcBlog/BcMail 等を含む)は全部消えて無効化される。復元後に必ず再有効化する: コア標準6つUPDATE plugins SET status=1 WHERE name IN ('BcBlog','BcMail','BcUploader','BcSearchIndex','BcThemeConfig','BcWidgetArea')+移行対象のうち確認済みのもの(動作確認工程中なら移行対象は 0 のままでよい)。BcDbMigrator/BcAddonMigrator の行も消えるので、引き続き使うなら再 INSERT。実施後bin/cake cache clear_all。 - ★
sitesテーブルも同様に上書きされ、テーマ適用が外れる(実測): 復元後は全サイトtheme='BcThemeSample'に戻る(BcDbMigrator 変換の既定値。マルチサイトの各行も v4 から復元される)。フロントを開くとMissingLayoutException(探索パスに自作テーマが無い)で気づく。復元後にテーマを再適用:UPDATE sites SET theme='<CamelCaseTheme>' WHERE id=<対象サイト>+キャッシュクリア。=**「復元後の再設定3点セット: plugins 再有効化・sites.theme 再適用・cache clear_all」**として覚える。 - ★手動導入したツールプラグイン(BcDbMigrator / BcAddonMigrator 等)も plugins テーブルごと消える(復元は v4 由来の plugins で上書きするため。実測: 復元後に
bc_addon_migratorコマンドがUnknown commandになる)。ツールを再度使う場合は plugins テーブルへ再 INSERT(+cache clear)してから実行する。 - ★マルチサイトは復元後に
site_idの整合を必ず検証する(実測・不整合あり): 復元データはテーブルごとに site_id の変換が食い違うことがある —contents.site_idは「v4 の id +1」(5系標準・メイン=1)に変換される一方、sites.idは AUTO_INCREMENT で 2〜 に詰め直され、プラグイン系テーブル(search_indexes 等)の site_id は v4 のまま無変換。結果、サブサイトの contents が存在しない site_id を指し、サブサイトURL(/blog/等)が全部 404 になる。検証SQL:SELECT site_id, COUNT(*) FROM contents GROUP BY site_idとSELECT id, alias FROM sitesを突き合わせる。修正は「5系標準=contents の付番(v4 +1)」に他を合わせる:sites.idと各テーブルの site_id を降順に UPDATE(衝突回避)し、ALTER TABLE sites AUTO_INCREMENT=<最大+1>。site_id カラムを持つテーブルはinformation_schema.COLUMNSで洗い出す。再復元すると不整合も再発するので、統一SQLを控えておき復元のたびに再実行する。 - 復元前に管理画面が 500 になる場合、(b)変換組プラグインの無効化で回避してよい: (b)組は boot/描画経路の4系残骸(Event リスナーの
viewVars参照等)で管理画面を壊しがち。上記のとおり復元は無効でもテーブルを取り込むので、UPDATE plugins SET status=0 WHERE name IN (...)+キャッシュクリアで管理画面を復旧させてから復元してよい(どのみち動作確認工程では一旦全無効化する)。
- 復元は zip の中身基準で動く(実装確認済み):
- バックアップ (v4): baserCMS 4 管理画面「データメンテナンス」でバックアップを作成し、ダウンロードした zip を
-
注意点:
- ★予約語カラム対応(復元前に必ず設定):
config/install.phpのDatasources.defaultに'quoteIdentifiers' => trueを復元前に必ず入れる。4系サイトはメールフォーム項目由来のcheck・message等の予約語カラムをほぼ確実に持っており、未設定だと復元がSQLSTATE[42000] 1064 Syntax error ... near 'check'で途中失敗する。「必要になる場合がある」ではなく既定で設定してよい(quote されて困ることはない)。 - ★復元の途中失敗は「users が空」を招く(復旧手順): 復元は zip 内スキーマの drop→create を先に行うため、途中で失敗すると users=0 のままになりログイン不能になる(MySQL は DDL がロールバックされない)。復旧は再インストールが確実:
mv config/install.php config/install.php.bak+.envのINSTALL_MODE="true"(install.php が残っていると「インストール済み」扱いで bootstrap が空DBを参照して落ちる)- DB を DROP→CREATE し
bin/cake install <URL> <メール> <パス> <DB名> --baseurl /v5/ --host <DBホスト> --username <ユーザー> --password <パス> INSTALL_MODEを false に戻し、再生成された install.php にquoteIdentifiersを再設定、プラグインのpluginsINSERT・migrations migrate -p・sites.themeを再適用- ブラウザ復元をやり直す。復元中はログアウトしないよう依頼しておく
- 復元直前・直後のログインの注意: 再インストールやDB作り直しの後は、ブラウザに古い CSRF クッキーが残っていて
Missing or invalid CSRF cookieになる → ログインページを再読み込みしてからログインしてもらう。復元成功後は users が v4 のものに置き換わるため、以後のログインは v4 と同じ管理者ID/パスワードになる(事前にユーザーへ伝えておく)。 - プラグイン(復元との順序): 標準フローでは変換(早期)→ プラグイン棚卸し/導入・有効化 → 復元の順とする。なお実装上、復元自体は zip の中身基準で動きテーブル取り込みにプラグインの有効/無効は影響しない(上記「復元は zip の中身基準で動く」参照)。順序を守る実利は「復元前に有効化まで済ませておくことで、復元後すぐ管理画面でプラグインデータを確認できる」「zip にスキーマが無いテーブル(Migrations でしか作られないもの)を先に作れる」こと。
- メモリ: バックアップ作成時にメモリーオーバーエラーとなる可能性があります。その際、ユーザーに php.iniの memory_limit の変更を促してください。
- 小数点: decimal(8,2) などを利用しているテーブルの場合、正常に移行できないので、別途、SQLで定義、インポートする必要があります。
- ★予約語カラム対応(復元前に必ず設定):
アップロードファイルの移行
/files ディレクトリを /v5/webroot/files に移動してください。
- v4 並行稼働中は「移動」でなく「コピー」にする(v4 側の表示を壊さない)。数GBあるためコンテナ内で
cp -aするのが速い。 - ★ネスト罠:
v5/webroot/filesは復元やプラグイン有効化の時点で既に一部生成されている(theme_configs/uploads/やブログのディレクトリ骨格など)。そのためcp -a /path/files /v5/webroot/filesとするとfiles/files/にネストしてコピーされる。既存ディレクトリへのマージはcp -a /path/files/. /v5/webroot/files/(末尾/.)で中身をコピーする。ネストしてしまったらcp -a .../files/files/. .../files/ && find .../files/files -deleteで解消。 - 未移行時の症状: アイキャッチ等のアップロード系URLは、実体ファイルが無いとヘルパのフォールバックで**ルート相対
/files/...(サブディレクトリ無し)**が出力され、v5 ページから v4 の files を誤参照する(v5 のerror.logにMissingRouteException: /files/...が並ぶ)。files 移行後は/v5/files/...が正しく生成される。この工程は「プラグイン有効化→描画確認」より前に済ませること。 - 移行後の検証: 描画HTMLの
srcをcurl | grep -o 'src="[^"]*files[^"]*"'で抜き、静的配信の 200 を確認する。ローカル環境では DB は最新なのに files が古い(本番から持ってきた時期のズレ)ことがあり、その 404 は移行起因ではない — v4 側の同パスにも実体が無いことで切り分ける。
主题转换
使用 BcAddonMigrator 插件转换主题。
- 准备:将 baserCMS 4 的主题文件夹压缩为 ZIP 文件。
- 重要:压缩时,不要包含主题目录的父目录(
theme/),必须以主题目录本身作为根目录。 - 步骤示例:
# 1. 确定主题名称(检查数据库中的 site_configs 表) # 示例:SELECT value FROM site_configs WHERE name = 'theme'; # 结果:my-custom-theme # 2. 将主题目录名转换为驼峰命名 # 示例:my-custom-theme -> MyCustomTheme THEME_NAME="my-custom-theme" # 替换为实际的主题名称 THEME_CAMEL="MyCustomTheme" # 转换为驼峰命名 # ★【最重要・注意数据破坏】如果转换后的名称与原名称仅大小写不同 # (例如:philosophy → Philosophy),在 macOS 等不区分大小写的文件系统中, # theme/<camel> 会被解析为与原目录相同的路径,删除临时副本时 # **会删除原主题本身**(确实会发生。如果是子模块, # 可通过 `git submodule update --init theme/<name>` 恢复)。 # 对于仅大小写不同的主题,不要复制到 theme/ 下,而是复制到临时目录: # 执行 cp -r "theme/${THEME_NAME}" "/tmp/${THEME_CAMEL}",然后在 /tmp 中压缩 cp -r "theme/${THEME_NAME}" "theme/${THEME_CAMEL}" # 3. 压缩为 ZIP(排除 node_modules) mkdir -p v5/tmp/zip cd theme zip -r "../v5/tmp/zip/${THEME_CAMEL}.zip" "${THEME_CAMEL}/" -x "*/node_modules/*" rm -rf "${THEME_CAMEL}" cd .. # 4. 确认压缩结果(重要) unzip -l "v5/tmp/zip/${THEME_CAMEL}.zip" | head -n 20 # 确认根目录为 MyCustomTheme/,且不包含 theme/ 目录
- 重要:压缩时,不要包含主题目录的父目录(
- 工具:在 baserCMS 5 中安装并启用
BcAddonMigrator(从 GitHub 获取)。 * 注意:从 GitHub 获取BcAddonMigrator,并将其放置在plugins/BcAddonMigrator。可以通过直接向plugins表执行 INSERT 来启用(因为它没有安装迁移;已验证。请参阅“启用插件(直接操作数据库・标准)”一节的步骤 2)。不可使用cake plugin load/直接编辑config/plugins.php。 - 转换(命令行):使用
bc_addon_migrator命令转换主题。# Docker 环境 THEME_CAMEL="MyCustomTheme" # 替换为实际的驼峰命名主题名 docker exec <container-name> bash -c "cd v5 && bin/cake bc_addon_migrator --type=theme tmp/zip/${THEME_CAMEL}.zip" # 输出:v5/tmp/${THEME_CAMEL}_5.2.0.zip - 放置:将转换后的 ZIP 文件解压到
v5/plugins/。THEME_CAMEL="MyCustomTheme" # 替换为实际的驼峰命名主题名 cd v5/tmp && unzip -q -o "${THEME_CAMEL}_5.2.0.zip" -d ../plugins/- 注意:转换并不完整。务必目视检查全部代码,并进行手动修正。
- 手动修正:
- 模型数据:将数组访问(
$post['BlogPost']['name'])改为实体属性($post->name)。 - URL:在数组形式的链接中添加
'plugin'键,并将控制器名改为大驼峰命名(例如:'controller' => 'search_indexes'→'controller' => 'SearchIndexes')。 - 表单:将
$this->BcForm->create('Model')改为$this->BcForm->create($entity)或null。将input()改为control()。 - 元素:将路径指定改为
PluginName.element_name格式。
- 模型数据:将数组访问(
插件转换
转换插件时也使用 BcAddonMigrator 插件。
不过,有时 GitHub 仓库等渠道已经发布了适用于 baserCMS 5 的版本。这种情况下,请直接使用该版本,不要进行转换。
插件清点(转换前必须执行・逐个插件确定方案)
在批量转换插件之前,逐个清点插件,并与用户确认是“转换 4 系版本”还是“使用现有的 5 系版本”,然后再决定。不要一开始就将所有插件交给 BcAddonMigrator 转换(否则会导致官方或作者已经发布 5 系版本的插件需要重复维护)。
- 调查:确认每个插件的① baserCMS 官方 5 系是否已标准内置(是否已整合到
baser-core/bc-*)② 作者/发布方的 GitHub 或 baser 市场是否有适配 5 系的版本 ③ 是否另行提供用于对接外部 SaaS 等的 5 系版本。判断依据不足的项目标记为“需确认”。 - 分类并向用户说明(示例):
- (a) 使用现有的 5 系版本:已整合到官方版本,或作者已发布 5 系版本的项目(例如:编辑器类、OGP 类等外部发布的项目)。→ 从转换对象中排除,通过 composer/管理界面安装 5 系版本。
- (b) 转换 4 系版本后迁移:自行开发且没有 5 系版本的项目(例如自家插件)。→ 使用
BcAddonMigrator转换 → 将内部代码升级到 5 系。 - (c) 废弃/不再需要:已被 5 系标准功能吸收,或不再使用的功能。→ 不迁移。
- 通过表格达成共识:创建“插件名称/在 4 系中的作用/是否有 5 系版本及获取途径/方针 (a/b/c)”列表,先与用户确认 (a)(b)(c),再进入下一阶段。主题也应以同样方式梳理。
- 将梳理结果反映到迁移计划(plan/spec)中,仅将 (b) 类项目纳入转换阶段。
- ★对于 (a) 类中非公开发布、需购买、需授权等 Agent 无法自行获取的项目,应在梳理表中明确区分,并与用户协商确认、记录“由谁在何时获取/安装”。仅将项目归类为“(a) 使用现有的 5 系版本”,会导致获取和安装的负责人及期限悬而未决,执行阶段往往会遗漏(实际案例:梳理文档中记录的编辑器类插件 5 系版本因非公开发布,需要由用户获取,但后续阶段未能完成安装,迁移完成后才发现前端显示错乱。原因是梳理表创建后便未再更新,也没有跟踪执行情况)。
- ★梳理工作不能止于创建表格;在宣布迁移完成前,必须核对梳理表与实际安装情况。逐项确认 (a) 类项目“是否已安装”;如仍有未安装项目,不要将其搁置在迁移计划范围之外,而应重新与用户确认处理时间(本次处理/作为单独任务继续处理)后再宣布完成。
- 准备:将 baserCMS 4 的插件文件夹压缩为 ZIP。
- 重要:与主题相同,压缩时不要包含父目录(
app/Plugin/),而应让插件目录本身成为压缩包根目录。 - 步骤示例(批量压缩所有插件):
# 移动到 app/Plugin/ 并压缩所有插件(排除 node_modules) mkdir -p v5/tmp/zip cd app/Plugin for d in */; do name=${d%/} zip -q -r "../../v5/tmp/zip/${name}.zip" "$name" -x "*/node_modules/*" done cd ../..
- 重要:与主题相同,压缩时不要包含父目录(
- 转换(命令行):使用
bc_addon_migrator命令批量转换所有插件。# Docker环境の場合 docker exec <container-name> bash -c "cd v5 && for zip in tmp/zip/*.zip; do bin/cake bc_addon_migrator \"\$zip\"; done" # 输出:v5/tmp/<PluginName>_5.2.0.zip(每个插件一个) - 部署:将转换后的 ZIP 文件批量解压到
v5/plugins/。cd v5/tmp && for zip in *_5.2.0.zip; do unzip -q -o "$zip" -d ../plugins/; done && cd ../.. - 清理:删除不需要的 ZIP 文件。
rm -rf v5/tmp/zip v5/tmp/*_5.2.0.zip- ★不要删除
baserbackup_*.zip(已完成 DB 转换的备份)。由于v5/tmp/中也存放着 BcDbMigrator 输出的 zip,因此请限定通配符的目标,仅匹配转换过程中间 zip(<PluginName>_<version>.zip)。 - 如果环境因 Bash 权限而拒绝执行
rm -rf,请使用find <path> -delete(例如:find v5/tmp/zip -delete。单个文件可用find v5/tmp -maxdepth 1 -name '<Name>_*.zip' -delete)。 - 注意:转换并不完整。务必目视检查全部代码,并进行手动修正。
- BcAddonMigrator 会做/不会做的事(实测):
- 会做:将
Controller/Model/View转换为src/命名空间;将admin_方法分离到Controller/Admin;生成src/<Name>Plugin.php(空类class <Name>Plugin extends BcPlugin {});将config.php/setting.php转换为 return 数组。 - 不会做:将
config/Schema(4 系 CakeSchema)转换为config/Migrations(4 系 Schema 会原样保留);移除config/init.php(会作为残留保留);将内部代码升级为 5 系(ClassRegistry、$this->data等会继续保留)。 - 因此,转换后出现“可以部署且
php -l检查通过,但没有 Migrations、仍有 4 系残留”属于正常状态。对于恢复运行,不会影响启用(参见“插件启用(直接操作 DB・标准)”一节)。生成 Migrations、清理残留、将内部代码升级为 5 系将在横向检查步骤(流程 15-17)中完成。
- 会做:将
- ★不要删除
- 手动修正:
- 目录结构:控制器中带有
admin_前缀的方法已移至Controller/Admin命名空间。 - 配置文件:调整
config/setting.php中BaserCore.nav等的数组结构。此外,将$config变量定义改为直接return数组的形式。- 重要:将
array()语法改为[](短数组语法),并整理缩进。 - 重要:如果存在多个
$config['Key']定义,请将它们合并到一个return数组中。 - 重要:注意避免自动转换后形成
return [ $config = [...] ];这样的多重结构。请删除$config =,改为纯粹的数组定义。 - 重要:如果需要引用自身配置,请先将其定义为局部变量,再进行引用。
- ★
adminNavigation的url中,plugin 和 controller 都应使用 CamelCase(例如'plugin' => 'PopularBlogPost', 'controller' => 'PopularBlogPostConfigs')。如果保留 4 系的 snake_case,公共侧边栏生成 URL 时会触发 MissingRouteException,导致不仅该插件,所有管理页面都会返回 404(这是集成测试中发现的实际案例)。4 系专用的adminNavi区块在 5 系中未使用,可以删除。
- 重要:将
- 生成迁移文件(bake migration_snapshot):
- 单独对插件执行
bake migration_snapshot -p [PluginName] --table [TableName]时,有时无法正确提取表定义(会生成空文件)。 - 此时,较可靠的做法是批量执行
bin/cake bake migration_snapshot GlobalInitial,获取所有表的状态,再将生成的代码手动(或通过脚本)分配到各插件的Initial.php中。
- 单独对插件执行
- $autoId 属性:
- 生成快照时,
$autoId = false是为了准确还原现有数据库结构,涵盖从列名到索引、注释等所有内容。 - 不要依赖自动生成,而应使用
addColumn显式定义所有内容,以消除与迁移源数据库的差异。
- 生成快照时,
- [重要] 数据库设置中,
v5/config/install.php的优先级高于v5/config/app_local.php。检查或更改设置时,请同时留意这两个文件。 - [重要] 不要直接编辑
v5/config/plugins.php。在 baserCMS 5 中,通过插件管理页面启用的插件会自动加载。直接编辑此文件可能导致依赖关系或路由(routes.php)加载顺序不一致,从而造成应用程序崩溃。 - [重要] 不要修改 baserCMS 本体(例如
baser-core)以及软件包中原本自带的插件(例如bc-admin-third等目录名包含连字符的核心插件)。这些内容会受本体更新影响,因此请将其排除在迁移工作范围之外。 - [重要]
BcAddonMigrator会自动移动带有admin_前缀的方法,但这些方法所调用的protected方法或_setFormViewData等辅助方法仍会留在原来的(前台)控制器中。请手动将它们移至管理控制器(Controller/Admin),并修正命名空间及所需的use语句。 - 插件信息:同样请确认
config.php采用 return 数组的形式(BcAddonMigrator会自动转换,但仍建议检查)。 - 初始化处理:
config/init.php已废弃。请创建src/[PluginName]Plugin.php(类名:[PluginName]Plugin),并继承BaserCore\BcPlugin。- 不需要
$this->Plugin->initDb()(因为会自动执行迁移)。 - 如果还有其他初始化逻辑,请将其移至
install()或bootstrap()方法。 - 重要:
install方法的签名必须为public function install($options = []): bool,并返回parent::install($options)的结果(或true)。
- 不需要
- Schema:
Config/Schema已废弃。请迁移至 CakePHP Migrations(config/Migrations)。 - Feed:Feed 插件已废弃,请考虑替代方案。
- 目录结构:控制器中带有
プラグインの有効化(DB直接・標準)
配置した移行対象プラグインの有効化は、plugins テーブルへの直接 INSERT を標準とする。ブラウザ往復ゼロでエージェントが自走でき、検証も SQL で完結する(管理画面有効化は代替手段として注記参照)。
★テーマは plugins テーブルに登録しない(新規インストール直後の plugins にデフォルトテーマ BcFront の行が無いことから実証済み)。テーマの適用は次節「テーマの適用(DB直接)」の sites.theme UPDATE のみでよい。
- 有効化前チェック(プラグインごと):
ls v5/plugins/<Name>/config/Migrationsで Migrations の有無を確認する。- (a)既存5系版のプラグインは通常 Migrations を持つ(有効化時にテーブル作成が必要)。
- (b)
BcAddonMigrator変換組は通常 Migrations を持たない(4系config/Schemaが残っているだけ)。復元 zip にスキーマ+データが含まれるかをunzip -l v5/tmp/baserbackup_*.zip | grep -iE "<table名>"で確認し、含まれていれば復元がテーブルを供給するので Migrations 生成は不要(クリーンインストール運用にする場合のみbake migration_snapshotで生成)。
pluginsテーブルへ INSERT(全プラグイン共通):
複数件あるときは priority を連番でずらす。INSERT INTO plugins (name, title, version, status, db_init, priority, created, modified) VALUES ('<Name>', '<Name>', '<version>', 1, 1, (SELECT p FROM (SELECT COALESCE(MAX(priority),0)+1 AS p FROM plugins) tmp), NOW(), NOW());- Migrations を持つプラグインはマイグレーションを併走(INSERT だけではテーブルが作られない):
docker exec <container> bash -lc 'cd /var/www/html/v5 && bin/cake migrations migrate -p <Name>' - キャッシュ全消去:
bin/cake cache clear_all(プラグインロード構成が変わるため)。 - 検証は CLI 起動スモーク+SQL まで(この段階でブラウザ確認はしない):
SELECT name, status FROM pluginsで status=1、Migrations 実行組はSHOW TABLESでテーブル生成を確認し、bin/cake versionが fatal なくバージョン番号を返すこと(=有効プラグイン全部の bootstrap が通ること)を確認する。フロント/管理画面のブラウザ確認はまだ求めない — 内部コードが4系のままなので画面は出なくて正常。ブラウザ確認は動作確認工程(標準フロー17)以降。管理画面が必要になるのは復元(フロー12)だけなので、その直前に管理画面ログインだけ生存確認すればよい。
★有効化で顕在化する boot 経路の4系残骸(先に潰す)
(b)変換組を有効化すると、画面以前にアプリ起動(bootstrap)で fatal になる4系残骸が動き出す(php -l では捕まらない実行時エラー)。有効化後の bin/cake version スモークで1つずつ顕在化するので、最小修正(TODO マーカー付き)だけしてフロー15-16(本格5系化)へ先送りする。実測した典型パターン:
| 場所 | 症状 | 最小修正 |
|---|---|---|
src/Event/*EventListener.php | Class "<NS>\Event\ClassRegistry" not found(BcEvent が有効プラグインのリスナーを bootstrap で instantiate するため、コンストラクタ内の4系APIが即死) | ClassRegistry::isKeySet/getObject 分岐を削除し TableRegistry::getTableLocator()->get() 一本化 |
config/setting.php | Class "CakeLog" not found / Configure::load が配列を得られない | CakeLog::config() 等の実行文を除去(ログ設定は Phase 4 で Plugin::bootstrap へ)。$config['X'] = [...] は return ['X' => [...]] へ |
config/setting.php 内の4系定数 | Undefined constant "CACHE_DATA_PATH" 等 | 5系の定数(TMP・CACHE 等)へ置換 |
config/routes.php | Router::connect 静的呼び出し・CakeRequest・BcSite::findByUrl で fatal | ファイル全体を return; で無効化+旧定義をコメント保存(Phase 4 で RouteBuilder 形式に書き換え) |
スモークが通る(bin/cake version がバージョンを返す)までこの表の要領で潰す。
★CLI スモークの限界に注意: bin/cake version は Web リクエストと bootstrap 経路が一部異なり、BcEvent のリスナー生成起因の fatal(例: コンストラクタでの Table 即時取得→MissingTableClassException)をすり抜けることがある(実測)。CLI スモーク通過=Web も無事、ではない。Web 側の最終確認は管理画面の GET 統合テスト(工程17-b)か実ブラウザで行う。リスナーのコンストラクタでは Table を即時取得せず遅延取得にするのが安全。
- 直 INSERT が安全な根拠:
BcAddonMigratorが生成する Plugin クラスは空(class XxxPlugin extends BcPlugin {})で独自 install 処理を持たないため、管理画面有効化との差は「マイグレーション自動実行の有無」だけ。それは手順3で補える。独自のinstall()をオーバーライドしているプラグインだけは中身を確認し、必要なら管理画面から有効化する。 - (代替)管理画面のプラグイン管理から有効化するとマイグレーションが自動実行される。ユーザーがブラウザ操作できる状況ならこちらでもよい。
config/plugins.phpの直接編集は不可(既出の注意どおりクラッシュ要因)。- この工程で全対象を有効化するのは「復元でテーブル・データを取り込むため」(フロー12の前提)。復元が済んだら、動作確認工程(フロー17)の開始時に移行対象を一旦全部無効化し、確認対象+その依存だけを1つずつ有効化しながら進める(イベント干渉の切り分けのため)。無効化/再有効化は
UPDATE plugins SET status=0(/1) WHERE name='<Name>'+bin/cake cache clear_allで行える(テーブルとデータは残るので安全)。
テーマの適用(DB直接)
5系ではテーマは site_configs ではなく sites テーブルの theme カラムで管理される。適用も DB 直接更新を標準とする。
-- サイトごとに適用(マルチサイトは site 単位で theme を持つ。全サイト同一テーマなら WHERE 句なし)
UPDATE sites SET theme = '<CamelCaseTheme>' WHERE id = 1;
- 適用後は必ず
bin/cake cache clear_all(テーマ解決がキャッシュされるため)。 - 検証は実ブラウザでフロントを開き、テーマのテンプレートが使われていること(500 でないこと)を確認。テーマ側テンプレートの4系残骸でエラーになる場合は、この時点では台帳に記録して工程15(テーマ横断チェック)で対応する。
プラグイン内部コードの変換(別スキル)
BcAddonMigrator で変換した後の プラグイン内部コードの具体的な書き換え(Controller の $this->Model→fetchTable、Table の initialize() アソシエーション宣言・find() クエリビルダ化、Entity/getControlSource、View/Helper、検索フォーム・編集フォームの BcAdminForm/control() 化、Time::format の ICU、Number::format/Text::truncate の null 対応、Vue・JS の $.bcUtil.adminBaseUrl 化と webpack 再ビルド、フロント表示エラーの症状別対処 等)は、専用スキル basercms-plugin-4-to-5-upgrade にカタログ化している。プラグインの画面を1枚ずつ通して動かす段階では、そちらを参照すること(C-0 機械一括変換カタログ/T- Table・ORM/C- Controller・画面/F- フロント表示エラーのうちプラグイン文脈分)。テーマ(templates 中心)の移行パターン(TH-系+テンプレート・テーマ描画系の F-系)は basercms-theme-4-to-5-upgrade スキルに分割している。変換先=5系の正しい書き方の正本は basercms5-plugin-development(プラグイン)/ basercms5-theme-development(テーマ)を参照。
移行の進め方(ユニットテスト先行 → ドメイン単位で画面結合)
BcAddonMigrator 変換後のプラグイン内部コードを手作業で5系化する工程は、次のワークフローで進めると速くて安全(実証済み)。目的は、任意の baserCMS4系プロジェクトを最小の手間で5系へ移行できる状態を作ること。
なぜこの順序か: 移行では「画面表示は動くのに、保存・集計・出力ロジックが静かに壊れている」ケースが多い(按分計算・集計の戻り値形状・絞り込み条件・本番に無い列など、目視では正しさを判断できない)。一方でユーザーの最大の手間は画面テストのリロード反復。テストはAIが自律実行でき人手が要らない。よって テストで正しさを固めてから、画面結合をまとめて1回 が最も手間が少ない。
- フェーズ1: ロジックをテスト駆動で移行(人手ほぼ不要)。対象ドメイン(見積/請求/売上/集計 等)の Table/保存/集計/出力ロジックを、責務を整理しつつ TDD で5系化。Factory+ユニットテストで「4系と同値」を数値で固定(RED→GREEN・回帰自動担保)。→ テスト基盤は basercms-unittest、変換パターンは basercms-plugin-4-to-5-upgrade(T-/C-/F-)。
- フェーズ2: 薄いグルー層。コントローラは「受け→Table/Service呼び→set」の薄さに保ち、ロジックはテスト済みの Table/Service へ寄せる。画面で確認すべき面積(テスト不能なグルー)を最小化。
- フェーズ3: ドメイン単位で画面結合を1回。ロジックが全部緑になってから、1回の画面セッションでテンプレート/JS・Vue/遷移/CSV・Excel/通知の結合を確認。事前に「どの画面で何を操作し何が期待結果か」のチェックリストを用意し、ユーザーは順に1往復するだけにする(リロードを「メソッドごと」でなく「ドメインごと」に集約)。
- フェーズ4: スキルへフィードバック。一段落ごとに、再利用可能な知見を該当スキル(プラグイン内部コード→basercms-plugin-4-to-5-upgrade、テスト→basercms-unittest、サイト手順→本スキル、5系共通ルール→basercms5-development、5系の実装パターン→basercms5-plugin-development / basercms5-theme-development)へ反映。症状→原因→修正・コード断片・戒めまで残す。
結合タイミングはドメインごと(見積を固める→見積画面を1回確認→次は請求…)。問題を新鮮なうちに発見でき手戻りが小さい。
長丁場セッションの運用(コンテキスト肥大対策・こまめに /compact)
4→5移行は1セッションが普通のタスクより長くなりやすい(環境構築→DB移行→棚卸し→変換→ドメインごとの5系化…と工程が多い)。セッションが長引くと、コンテキスト肥大でアシスタントのツール呼び出しが壊れ始めることがある(症状: <invoke>/<parameter> の名前空間プレフィックス欠落や、先頭に無関係な語=例「court」が紛れ込んでコマンド/ツール呼び出しが失敗する。環境やシェルの不具合ではなく、アシスタント側の出力フォーマット崩れ)。
- 対処: この種の失敗が数回続いたら、粘って再試行せず早めに
/compactでコンテキストを圧縮してから続行する(要点は要約に引き継がれるので作業は継続できる)。工程の区切り(各フェーズ完了時など)でも予防的に/compactしてよい。 - 予防: 大きな中間成果物(計画・台帳・調査ログ)は会話に溜め込まず、spec/plan ファイルや scratchpad に書き出しておくと、compact 後も参照が楽で肥大も抑えられる。
Git / リポジトリ運用(移行コードのバージョン管理)
4系プラグインを
BcAddonMigratorで変換し v5 に配置した後、git に取り込む際の定番のハマりどころ。G-2〜G-4 はどのプロジェクトでも該当。G-1 は 4系で git サブモジュールを使っていたプロジェクト限定(多くのプロジェクトはサブモジュール未使用なので該当しない)。
G-1.【サブモジュールを利用している場合のみ】変換済みプラグインに残る4系サブモジュールの .git(gitlink)を除去
※ この項目は、4系でプラグインを git サブモジュール(.gitmodules に登録)として管理していたプロジェクトのみ対象。サブモジュールを使っていなければ .git は付いてこないので無関係(find v5 -name .git が 0 件なら該当なし)。
4系で git サブモジュールだったプラグイン(app/Plugin/<X>)をコピーすると、.git(gitlink ファイル)も付いてくる。これは gitdir: ../../../.git/modules/app/Plugin/<X>(=4系本体のサブモジュール格納庫)を指したままで、「同じ git モジュールに2つの作業ツリーが紐づく」「変換済み5系コードが4系HEADと全差分」等の矛盾を起こす。
- 対処:
find v5 -name .git -type f -deleteで v5 配下の gitlink ファイルを削除(実コード・.gitignore・4系の実サブモジュール/.git/modules/.gitmodulesには触れない=安全)。これで変換済みプラグインは「普通のディレクトリ」になる。
G-2. baserCMS5 標準 .gitignore は /plugins/* を無視する → 自作プラグインを negation
v5 同梱 .gitignore は /plugins/* を無視し、コア/サンプル(!/plugins/baser-core, !/plugins/bc-*, !/plugins/BcColumn 等)だけ negation で追跡する設計。そのままでは変換済みの自作プラグインが追跡対象外になる。
- 対処: 自作プラグインを
!/plugins/Sampleのように negation 追記(git check-ignore v5/plugins/Sampleが空=追跡可、で確認)。/plugins/*/vendor・/plugins/*/node_modules・/plugins/*/composer.lock・schema-dump-default.lockは無視のまま。
G-3. アップロード実体 webroot/files/* は git に含めない
v5 標準 .gitignore は /webroot/files/* を無視する(正しい既定)。4系から移行したアップロード(本プロジェクトは 1.7GB / 1万超ファイル)を git に入れると repo 肥大化・clone 遅延・GitHub 制限で push 不可になり得る。除外のままにし、実体は別途バックアップ/再コピーで運用する(!/webroot/files/.gitkeep で空ディレクトリ保持)。git add -n v5 | wc -l 等で巨大物の混入を事前確認するとよい。
G-4. v5 のネスト/取り込み
git add v5 時、ネストした v5/.gitignore は親リポジトリでもそのまま効く(秘匿 config/.env・app_local.php・vendor・tmp・logs は自動除外される)。git add -n(dry-run)でステージ予定を必ず検証してからコミットする。プラグインを将来「再利用可能な独立リポジトリ」にしたい場合も、まずは親に通常ファイルで取り込み、安定後に git subtree split で切り出す段階移行が扱いやすい。
注意事項
- コードを提案する際は、必ず CakePHP 5.0 の公式ドキュメントおよび baserCMS 5 のソースコード(
vendor/baserproject/以下)との整合性を確認してください。 - 「たぶん動く」CakePHP 2 のコードを残さないでください。
- [重要] ターミナルコマンドを実行する際は、バックグラウンド実行(
&を末尾につける、またはツールのWaitMsBeforeAsyncを短く設定して放置するなど)を行わないでください。処理が滞留し、後続の操作を受け付けなくなる可能性があります。必ず同期的に完了させてください。