mcpField
B
basercms-plugin-5x-update

basercms-plugin-5x-update

github.com/baserproject開発040 回インストール6 日前に更新
リポジトリ

basercms-plugin-5x-update について

baserCMSプラグインを5.2から5.3へ移行する担当者向けのガイドです。独立型プラグインのテスト、プラグイン読み込み、非推奨項目、テストデータの問題と対処法をまとめています。

主な機能

  1. 01baserCMS 5.2から5.3への移行情報
  2. 02独立型プラグインのテスト調査
  3. 03プラグイン読み込みと設定の規則
  4. 04非推奨コードの修正案
  5. 05フィクスチャと日付依存テストの診断

活用シーン

  1. 01プラグインを5.2から5.3へ更新
  2. 02移行後の統合テスト失敗の調査
  3. 03プラグイン重複読み込みやクラス欠落の特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/baserproject/baser-skills --skill basercms-plugin-5x-update

インストール後、Claude Code で/basercms-plugin-5x-updateを入力して読み込まれたか確認します。

詳細

プロジェクトの README より

baserCMS プラグイン バージョン移行ガイド(5.2 → 5.3)

baserCMS プラグインを 5.2系 から 5.3系へ移行する際に遭遇した baserCMS 固有の問題と修正レシピ集。バージョン別に整理して育てる。

推奨: 着手前に一度 basercms5-claude-workflow-setup(環境セットアップ)を参照し、進め方の環境(設計=superpowers brainstorming/権限整理=permissions-audit/その上での Auto mode/spec・plan の Markdown プレビュー)を整える。提案ベースで、整っていればスキップ。

収録: 5.2 → 5.3。5.3系は PHP 8.5 / CakePHP 5.2.x ベース(執筆時点で開発中)。 役割分担:

  • PHP 本体起因(暗黙nullable・動的プロパティ・非正規キャスト・setAccessible・null オフセット等)→ php-migration スキル
  • CakePHP 本体/関連パッケージ起因(AbstractMigration→BaseMigration・イベント戻り値・PluginCollection・TreeBehavior・ResultSet・order()/group() 等)→ cakephp-migration スキル
  • ユニットテストの実行・集計・切り分け手順 → basercms-unittest スキル
  • 本書は上記に当てはまらない baserCMS 固有 + プラグインのテスト基盤 に絞る。

大原則

  • 「致命的エラー」と「非推奨警告」を区別する。logs/debug.log の debug: や logs/error.log の error: で …は非推奨です と出るものは警告(動作継続)。Fatal / Exception が本当のエラー。
  • テスト大量失敗は根本原因単位で分類する。数百件でも原因は十数種。例外メッセージを集計して systemic な原因(vendor 混在・プラグイン未ロード・フィクスチャ不正)から潰す。
  • 依存の更新は composer require を使い、composer update で依存全体を動かさない(cakephp-migration 大原則と同じ)。

5.2 → 5.3 の変更

0. 依存バージョンの更新(composer.json)

プラグインの require-dev(または require)の baser-core を 5.3 系に上げる。

"require-dev": {
    "baserproject/baser-core": "5.3.x"
}
  • 上げた後は composer update baserproject/baser-core --with-dependencies(プラグインの vendor を持つ場合)で 5.3 系 + CakePHP 5.2.x を取り込む。
  • PHP 要件は 8.1 互換を維持するなら "php": ">=8.1" のまま(8.5 の非推奨対応は php-migration の ❌ 印=据え置き方針に従う)。

テスト基盤(standalone プラグイン test harness)

自前 vendor/ と tests/TestApp/ を持つ「単体実行型」のプラグインを 5.3 で動かすと、ここが最も詰まる。コアプラグイン(親ディレクトリのアプリ経由でテスト)の場合はアプリ側 tests/bootstrap.php が同等の処理をしているので、本節はアプリ側を参照する。

T-1. CakePHP の二重ロード(vendor 混在)で validateUnique(): Argument #2 ($options) not passed

composer test が ルートの phpunit(../../vendor/bin/phpunit)を起動する一方、プラグインの tests/bootstrap.php が ROOT/vendor/autoload.php(=プラグイン自前 vendor)を読み込むと、2つの異なる CakePHP バージョンが同時にロードされる。Composer のオートローダは register(prepend=true) で後勝ちになるため、起動時に読まれたクラス(例 Cake\ORM\Table 5.0系)と実行時に初めて読まれるクラス(例 Cake\Validation\Validator 5.2系)が混在し、validateUnique() 等でシグネチャ不一致の ArgumentCountError が出る。

  • 判別: スタックトレースに …/vendor/cakephp/…(ルート)と …/plugins/<plugin>/vendor/cakephp/…(自前)の 両方が現れる。
  • 修正(standalone): テストはプラグイン自前の vendor/bin/phpunit で実行する。bootstrap が読む ROOT/vendor と phpunit bin の autoload が同一 vendor になり、CakePHP が単一バージョンに揃う。
    // plugins/<plugin>/composer.json
    "scripts": { "test": ["Composer\\Config::disableProcessTimeout", "vendor/bin/phpunit --colors=always"] }
    
    実行(Docker 経由・basercms-unittest 参照): docker compose exec <container> sh -c "cd /var/www/html/plugins/<plugin> && vendor/bin/phpunit"
T-2. plugins.php の null → [](CakePHP 5.2 の PluginCollection::create が array 必須)

tests/TestApp/config/plugins.php の値が null だと、BaseApplication::bootstrap() → PluginCollection::addFromConfig() → create($name, null) で TypeError: …create(): Argument #2 ($config) must be of type array, null given になる(5.1 までは許容)。

// Before → After
return ['BaserCore' => null, ...];  →  return ['BaserCore' => []];
  • 関連: cakephp-migration 1-4 にも同記述あり。
T-3. プラグインの読み込みは BcApp.testAppPluginsToLoad を使う(plugins.php は BaserCore のみ)

baser-core 5.2+ の BcTestCase::loadTestAppPlugins() は Configure::read('BcApp.testAppPluginsToLoad') を読み、未 bootstrap が無くなるまでスナップショット単位で(ガード付きで)各プラグインを bootstrap する。

  • plugins.php には BaserCore のみを記載し、コンテンツ系プラグイン(BcBlog / BcCustomContent / BcSearchIndex 等)と対象プラグイン自身は testAppPluginsToLoad に列挙する。本体アプリ(config/plugins.php は BaserCore + 基盤のみ、tests/bootstrap.php で Plugin::loaded() から testAppPluginsToLoad を生成)と同方式。
    // plugins/<plugin>/tests/bootstrap.php(Migrator の後など)
    Configure::write('BcApp.testAppPluginsToLoad', [
        'BcMcp',            // 対象プラグイン自身
        'BcSearchIndex', 'BcBlog', 'BcCustomContent', // 依存コンテンツプラグイン
    ]);
    
T-4. 統合テストで Plugin named 'X' is already loaded(二重ロード例外)

T-3 と必ずセットで守る。プラグインを plugins.php と testAppPluginsToLoad の両方に書くと、統合テストがリクエスト毎に生成する per-request app が plugins.php を再び addFromConfig し、既に読み込み済みのプラグインを再 add して CakeException: Plugin named 'X' is already loaded(CakePHP 5.2、cakephp-migration 2-7)になる。500 → さらに後述 T-6 でマスクされ「原因不明の 500」に見える。

  • 修正: BaserCore は plugins.php、その他は testAppPluginsToLoad に分離して重複させない。
T-5. 同梱サブプラグインのクラスが not found(例 Class "BcCcFile\Utility\BcCcFileUtil" not found)

BcCcFile は bc-custom-content に同梱されたサブプラグイン(vendor/baserproject/bc-custom-content/plugins/BcCcFile/)で、BcCustomContentPlugin::bootstrap() → loadPlugin() が App.paths.plugins を追加し BcUtil::includePluginClass() で動的に PSR-4 登録する。composer の autoload には現れないため、親プラグインが bootstrap されないとクラス解決できない。

  • 修正: 親プラグイン(BcCustomContent)を T-3 の testAppPluginsToLoad に入れて bootstrap させる。サブプラグインの namespace を composer.json に手書き登録する必要はない。
T-6. テストの真因が MissingTemplateException: Error/error500.php でマスクされる

standalone の test harness には templates/Error/error500.php が無いため、統合テストで発生した 500 が「エラーページのレンダリング失敗」に化けて本当の例外が見えない(debug の有無に関わらず baserCMS はエラーテンプレートを描画しようとする)。

  • 調査法(一時措置): plugins/<plugin>/templates/Error/error500.php を一時的に置き、テンプレートに渡る $error(Throwable)を捕捉してファイルへ書き出す → テスト実行 → 真因を確認 → テンプレートは削除する。
    <?php // TEMP: 調査用。確認後に削除
    $e = $error ?? null;
    if ($e) { file_put_contents('/tmp/real_error.txt', get_class($e).': '.$e->getMessage()."\n".$e->getTraceAsString()); }
    echo 'ERR500';
    
  • エラーレンダラーが探すのは プラグインの templates/Error/(tests/TestApp/templates/ ではない)点に注意。

baserCMS 固有の非推奨

B-1. BcFile のコンストラクタ/delete() のパス指定

logs/error.log に下記が出る(6.0.0 で必須化=今は警告)。

BcFile では、コンストラクタでパスの指定をしないのは非推奨です。パスの指定行うようにしてください。この要件はバージョン 6.0.0 で必須となります。
BcFile::delete() では、第一引数にパスを指定するのは非推奨です。パスの指定はコンストラクタで行ってください。この要件はバージョン 6.0.0 で必須となります。
  • 修正: パスはコンストラクタで渡し、delete() は引数なしにする。
    // Before → After
    $file = new BcFile();           $file = new BcFile($path);
    $file->delete($path);           $file->delete();
    
  • 自前プラグインのコードで BcFile を使っている箇所のみ対象(vendor 内の発生は baser-core 側の対応待ちで、プラグイン移行としては無視してよい)。

TreeBehavior + Content フィクスチャ

C-1. Cannot set a node's parent as itself.(Content 保存テスト)

CakePHP 5.2 の TreeBehavior は「親に自分自身」を保存時に例外化する(cakephp-migration 2-11 と同系の厳格化)。baserCMS のテストシナリオで顕在化しやすい典型:

  • BlogContentScenario 等は $parentId = $args[2] ?? 1 のように ?? 1 でデフォルトを与えるため、テストが null を渡しても parent_id=1 になる。id=1 のコンテンツだと parent_id == id(自己親) の不正データになる。
  • 読み取りテストでは無害だが、Content を保存するテスト(editXxx で name/title/site_id 等を更新し Content 関連が save される)でのみ例外化する。
  • 修正(テスト側): シナリオ読込後に Content を正当なルートへ補正してツリーを再構築する。
    $contentsTable = TableRegistry::getTableLocator()->get('BaserCore.Contents');
    $contentsTable->updateAll(['parent_id' => null], ['id' => 1]); // behavior を介さず is-a-root に
    $contentsTable->recover();                                     // lft/rght 再構築
    
  • プラグイン本体コードが parent_id をルートに対して送っていないか(cakephp-migration 2-11)も併せて確認する。送っていなければアプリ修正は不要で、上記フィクスチャ補正で足りる。

日付・時刻依存テスト

D-1. アップロードパス等の年月ハードコード

ファイルアップロード先は実行時の年月(date('Y/m'))でディレクトリが切られるため、'2025/09/...' のように固定値でアサートしていると月替わりで必ず失敗する。

// Before → After
$this->assertEquals('2025/09/00000001_image_field.png', $result['image_field'] ?? '');
$this->assertEquals(date('Y/m') . '/00000001_image_field.png', $result['image_field'] ?? '');
  • 時刻比較全般の注意は cakephp-migration 3-4(実 time() を使わない)も参照。

調査の進め方(チェックリスト)

  1. テスト実行・全失敗の集計は basercms-unittest スキル。まず vendor 混在(T-1) を疑い、トレースに 2 つの cakephp パスが無いか確認。
  2. PluginCollection::create(): … null given → T-2、Plugin named 'X' is already loaded → T-3/T-4。
  3. Class "…\…" not found(サブプラグイン)→ T-5。
  4. 統合テストの原因不明 500 → T-6 で真因を可視化してから分類。
  5. フレームワーク/PHP 起因は cakephp-migration / php-migration の該当節へ。baserCMS 固有非推奨は B-1、TreeBehavior は C-1、日付依存は D-1。
  6. 修正のたびに php -l → --filter 単体確認 → 仕上げに全テスト再実行で件数改善と新規回帰を確認。

メモ: 新しくスキルファイルを .claude/skills/ に追加・更新した直後は、現在の Claude Code セッションには反映されない(セッション起動時に discover される)。Claude Code を再起動すると /basercms-plugin-5x-update として呼べるようになる。

コメント