CakePHP 4 で別フォルダに置くコントローラを Bake Theme で自動生成

はじめに

今回も下記「一部コントローラを別フォルダ化」シリーズの続きで、これで一区切りにしようと思います。

前の投稿では Bake の方法をご紹介しましたが、今日は CakePHP 4 で別フォルダに置くコントローラを Bake Theme を使って自動生成する方法をご紹介します。

通常の Bake テーマ につきましては「CakePHP 4 で 独自の Bake テンプレートを Theme としてつくり、作業効率を向上!」でご紹介しています。

検証に使用したのは CakePHP 4.1.5 (cakephp/app 4.1.1) です。

目次
  1. 下準備
  2. 設定変更
  3. テンプレート作成
  4. 独自の Bake オプションを追加
  5. おわりに

1. 下準備

ファイル構成は下記のようになります。

/path/to/cakephp4/
    ├ plugins/
    │  └ MyBakeTheme/
    │      ├ src/
    │      │  └ Command/
    │      │      ├ AjaxCommand.php
    │      │      └ AjaxTestCommand.php
    │      │
    │      └ templates/
    │          └ bake/
    │              └ Ajax/
    │                  └ controller.twig
    ├ src/
    │  ├ Ajax/
    │  │  └ AppController.php
    │  (他省略)
    │
    ├ tests/
    │  ├ TestCase/
    │  │  ├ Ajax/
     (他省略)

これまで同様 Ajax 用コントローラを別フォルダに置く想定で、
Bake テーマは「MyBakeTheme」という名前にしています。

自動生成するコントローラとテストも前回で同じく、
それぞれ /src/Ajax と /tests/TestCase/Ajax に出力します。

Ajax/AppController の内容はこれまでと同じで、下記になります。

/src/Ajax/AppController.php
<?php
declare(strict_types=1);

namespace App\Controller\Ajax;

use Cake\Controller\Controller;

class AppController extends Controller
{
}

2. 設定変更

Bake コマンドで「MyBakeTheme」を使うための設定を行います。

/config/bootstrap_cli.php
// ▼末尾などに下記を追加
Configure::write('Bake.theme', 'MyBakeTheme');

通常の Bake Theme はこれで済むのですが、今回は Bake のオプション(AjaxCommand.php など) を追加する関係で、/composer.json と /src/Application.php にも追記が必要になります。

composer.json は下記のように追記し、dump-autoload コマンドで autoload ファイルを更新します。

/composer.json
"autoload": {
    "psr-4": {
        "App\\": "src/",
        "App\\Controller\\Ajax\\": "src/Ajax/", ← 末尾の , 追加を忘れずに
        "MyBakeTheme\\": "plugins/MyBakeTheme/src/" ← これを追加
    }
},
$ cd /path/to/cakephp4
$ composer dump-autoload

App\\Controller\\Ajax\\ の指定については、過去の「CakePHP 4 で一部のコントローラを別フォルダに設置する方法」をご参照ください。

Application.php には下記1行を追加します。

/src/Application.php
public function bootstrap(): void
{
    // ↓ 追加
    $this->addPlugin('MyBakeTheme');
    ...
}

3. テンプレート作成

Ajax 用コントローラのための Bake テンプレート追加します。
内容は前回と同じで、置く場所が違うだけです。

/plugins/MyBakeTheme/templates/bake/Ajax/controller.twig
<?php
declare(strict_types=1);

namespace {{ namespace }}\Controller\Ajax;

class {{ name }}Controller extends AppController
{
    public function index()
    {
        $vars = [];

        $this->set($vars);
        $this->viewBuilder()
            ->setClassName('Json')
            ->setOption('serialize', array_keys($vars))
            ->setOption('jsonOptions', JSON_FORCE_OBJECT);
    }
}

4. 独自の Bake オプションを追加

Ajax 用コントローラとテストを生成するための Bake オプションを MyBakeTheme に実装します。

こちらも前回とほぼ同じ内容ですが、namespace が異なるのでご注意ください。

/plugins/MyBakeTheme/src/Command/AjaxCommand.php
<?php
declare(strict_types=1);

namespace MyBakeTheme\Command;

use Bake\Command\SimpleBakeCommand;
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;

class AjaxCommand extends SimpleBakeCommand
{
    public $pathFragment = 'Ajax/';

    public function fileName($name): string
    {
        return "{$name}Controller.php";
    }

    public function name(): string
    {
        return 'Ajax';
    }

    public function template(): string
    {
        return 'Ajax/controller';
    }

    public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void
    {
        if ($args->getOption('no-test')) {
            return;
        }
        $test = new AjaxTestCommand();
        if (!isset($test->classSuffixes[$this->name()])) {
            $test->classSuffixes[$this->name()] = 'Controller';
        }

        $name = ucfirst($this->name());
        if (!isset($test->classTypes[$name])) {
            $test->classTypes[$name] = 'Controller\Ajax';
        }

        $test->plugin = $this->plugin;
        $test->bake($this->name(), $className, $args, $io);
    }
}
/plugins/MyBakeTheme/src/Command/AjaxTestCommand.php
<?php
declare(strict_types=1);

namespace MyBakeTheme\Command;

use Bake\Command\TestCommand;
use Cake\Core\Configure;

class AjaxTestCommand extends TestCommand
{
    public function testCaseFileName(string $type, string $className): string
    {
        $namespace = $this->plugin ?? Configure::read('App.namespace');

        $base = $this->getBasePath();
        $file = str_replace("{$namespace}\\Controller\\", '', $className). 'Test.php';
        $path = str_replace(['/', '\\'], DS, "{$base}{$file}");

        return $path;
    }
}

上記2つのコマンドを追加すると bake のオプションに ajax が表示されます。
(ajax_test も出ちゃいますが無視してください)

$ bin/cake bake -h
...
MyBakeTheme:
 - bake ajax
 - bake ajax_test

あとは bake ajax コマンドを実行すれば、Ajax 用コントローラとそのテストファイルが自動生成されます。

# テスト付き
$ bin/cake bake ajax SampleOne

# テスト無し
$ bin/cake bake ajax SampleTwo --no-test

5. おわりに

今回は通常の Bake Theme と違って composer.json への追記を行いました。公式ドキュメントでは解決策が見つからず、プラグイン作成の経験からこのように実装したところ動作しました。

Bake Theme は複数パターンのコントローラやテンプレなどを自動生成したい時に使えると思います。また異なる Bake テンプレートを共存させることができるので、開発効率がよくなったりもします。

やってみるとそれほど難しくないと思いますので、是非使ってみてください。