mcpField
B
basercms-plugin-5x-update

basercms-plugin-5x-update

github.com/baserprojectDevelopment040 installsUpdated 6d ago
Repository

About basercms-plugin-5x-update

A migration guide for baserCMS plugin maintainers moving from 5.2 to 5.3, cataloging version-specific issues and fixes. It focuses on standalone plugin tests, plugin loading, deprecations, and test data problems.

Key features

  1. 01baserCMS 5.2 to 5.3 migration notes
  2. 02Standalone plugin test troubleshooting
  3. 03Plugin loading and configuration rules
  4. 04Deprecated usage remediation
  5. 05Fixture and date-related test diagnosis

Use cases

  1. 01Upgrading a plugin from 5.2 to 5.3
  2. 02Diagnosing integration test failures after migration
  3. 03Finding duplicate plugin loads or missing classes

Install

Copy the command and run it in a terminal.

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

After installing, type/basercms-plugin-5x-updatein Claude Code to confirm it loaded.

Details

From the project 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 として呼べるようになる。

Comments

Markdown supported