CakePHP 4 で一部のコントローラを別フォルダに設置する方法

はじめに

CakePHP 4 は MVC モデルが採用されているフレームワークで、各種ファイルを格納するフォルダが明確にされています。

また CakePHP 4 には Ajax や Web API 用の機能も充実しているのですが、それらの機能も通常のアクションと同じように Controller に書きます。

例えば通常のアクションと Ajax 用アクションが共存するシステムの場合、コントローラの肥大化防止策としてファイル分割が考えられます。

しかし、次の悩みとして Controller フォルダ内のファイルが増えてしまい、作業効率が低下する可能性が出てきます。

そこで今日は CakePHP 4 で一部のコントローラを別のフォルダに設置する方法をご紹介します。

/src/Controller フォルダの移動ではなく、コントローラの一部を別フォルダに移動です。

動作確認に使用したのは CakePHP 4.1.5 (cakephp/app 4.1.1) です。

目次
  1. 下準備
  2. composer.json に namespace と フォルダの設定追加
  3. コントローラ設置
  4. ルーティング設定
  5. おわりに

1. 下準備

今回は Ajax 専用コントローラを作るケースを想定し、
下記のように /src/Ajax にそれらを置くことにします。

/path/to/cakephp4/
  ├ src/
  │  ├ Ajax/
  │  │  ├ AppController.php
  │  │  └ SampleController.php
 (他省略)

上記の AppController.php は /src/Ajax/ に置く各クラスで継承するもので、ファイル名は変更しても差支えありません。
(これを使わない方法も含め、詳細は後述します)

また、今回ご紹介する方法の概要を以下にまとめます。

  1. /src/Ajax に設置するコントローラの namespace は /App/Controller/Ajax にする
  2. /composer.json で上記 namespace のディレクトリを指定
  3. /src/Ajax にコントローラ作成
  4. /config/routes.php でルーティング設定

2. composer.json に namespace と フォルダの設定追加

composer.json の autoload に、下記のように追記します。

/composer.json
"autoload": {
    "psr-4": {
        "App\\": "src/", ← 末尾の , 追加を忘れずに
        "App\\Controller\\Ajax\\": "src/Ajax/" ← これを追加
    }
},

追加したら下記コマンドで autoload ファイルを更新します。

$ cd /path/to/cakephp4
$ composer dump-autoload

追記した内容が反映されるファイルは
/vendor/composer/autoload_psr4.php と 同 autoload_static.php です。

3. コントローラ設置

/src/Ajax に置くコントローラは下記のようにしました。

どちらも namespace が App\Controller\Ajax ですのでご注意ください。

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

namespace App\Controller\Ajax;

use Cake\Controller\Controller;

class AppController extends Controller
{
}
/src/Ajax/SampleController.php
<?php
declare(strict_types=1);

namespace App\Controller\Ajax;

class SampleController extends AppController
{
    public function index()
    {
        $this->set('message', 'これはサンプルです');
        $this->viewBuilder()
            ->setClassName('Json')
            ->setOption('serialize', ['message'])
            ->setOption('jsonOptions', JSON_FORCE_OBJECT);
    }
}

Ajax/AppController は、通常の Controller/AppController に合わせて同じ名前にしていますが、別な名前に変えていただいても差し支えありません。
(その際は SampleController の extends の箇所も変更してください)

この Ajax/App... を作らずに、通常の Controller/App... を継承しても良かったのですが、「こんなこともできる」という意味も含めて、このような形でご紹介しました。

僕は Ajax/App... を用意すると Ajax 用コントローラだけの共通処理を書くときに便利だと思っています。

もう一方の SampleController は JSON を返すプログラムです。
詳しくは過去記事「CakePHP 4 で JSON 出力を実装する方法」をご参照ください。

もし /src/Controller/AppController.php を継承したい場合は、下記のようにすれば対応可能です。

/src/Ajax/SampleController.php
// ↓ 通常の AppController を継承する場合
use App\Controller\AppController;

class SampleController extends AppController

4. ルーティング設定

/src/Ajax に配置したコントローラへのルーティング設定を行います。

下記サンプルは https://example.com/ajax/sample のような形でアクセスできるようにしています。

/config/routes.php
$routes->scope('/', function (RouteBuilder $builder) {
    // ↓ 追加
    $builder->connect('/ajax/{controller}', ['prefix' => 'Ajax']);
    ...
}

作業はこれで完了です。

動作確認として、ブラウザで /ajax/sample にアクセスし JSON でメッセージが表示されるか確認してみてください。

ルーティング設定については CakePHP 4 の公式ドキュメントに様々な事例が紹介されていますので、参考にしながら適宜変更していただければと思います。

5. おわりに

適切なファイルの分割や配置は、作業効率の向上やストレス軽減に繋がります。

特にコントローラが大きかったり、ファイル数が多いプロジェクトでは、こういう小さな改善が効いてくるなと感じます。

逆に小さなプロジェクトでは、今回のような対応はしない方が効率的かもしれません。

ところで、この形でまだ試していないことがありまして、それは Bake と 自動テスト です。
このあたりについては今後試そうと思います。