CakePHP 4 で 独自の Bake テンプレートを Theme としてつくり、作業効率を向上!

はじめに

CakePHP には Bake と呼ばれる機能があり、これを使ってコントローラ、モデル、テンプレートなど、様々なコードのベースとなるものを自動生成することができます。

しかし初期設定のまま使うと、自分が作るコードとは異なる箇所が多く、結局大半を書き直すことになりがちです。

各種画面は同一システム内でフォーマットが似ることも多く、その形で出力できれば作業が一層効率化します。

そこで今日は CakePHP 4 の bake コマンドで使う独自のひな形(bake テンプレート)を作る方法を紹介します。

今回は articles テーブルの一覧画面のテンプレートを Bake で作成するサンプルをご紹介します。

本投稿の中で「テンプレート」という時には、各画面のテンプレート(/templates/Articles/add.php など)を意味し、「Bake テンプレート」というときには Bake で出力する各種ファイルのひな形のことで、/templates/bake/Template/index.twig などのファイルをさします。
CakePHP
4.0.5
PHP
7.3.15
OS
Windows 10 Home
目次
  1. 下準備
  2. Bake テンプレート作成
  3. 独自 Bake テンプレート作りのコツ
  4. おわりに

1. 下準備

まず、動作確認に使用したデータベースです。

CREATE TABLE articles (
  id int(11) NOT NULL,
  title varchar(255) NOT NULL,
  body text NOT NULL,
  created datetime NOT NULL,
  modified datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE articles
  ADD PRIMARY KEY (id),
  MODIFY id int(11) NOT NULL AUTO_INCREMENT;

INSERT INTO articles
  (id, title, body, created, modified)
VALUES
  (1, 'タイトル(1)', '本文(1)', NOW(), NOW()),
  (2, 'タイトル(2)', '本文(2)', NOW(), NOW()),
  (3, 'タイトル(3)', '本文(3)', NOW(), NOW());

コントローラは下記のようにしました。

/src/Controller/ArticlesController.php
<?php
declare(strict_types=1);

namespace App\Controller;

class ArticlesController extends AppController
{
  public function index()
  {
    $articles = $this->Articles->find()
      ->all();
    $this->set(compact('articles'));
  }
}

2. Bake テンプレート作成

Bake テンプレートの実装方法はいくつかありますが、個人的にはプラグイン(Bake Theme)として追加するのがおススメです。管理がしやすく、他プロジェクトで流用するときにも使いやすいと思います。

今回は MyBakeTheme というプラグイン名にしています。

/plugins/MyBakeTheme/templates/bake/Template/index.twig
<section>
  <h1><?= __('{{ pluralHumanName }}') ?></h1>

  <table>
    <thead>
      <tr>
{% for field in fields %}
        <th><?= __('{{ field }}') ?></th>
{% endfor %}
      </tr>
    </thead>
    <tbody>
      <?php foreach (${{ pluralVar }} as ${{ singularVar }}): ?>
        <tr>
{% for field in fields %}
          <td><?= h(${{ singularVar }}->{{ field }}) ?></td>
{% endfor %}
        </tr>
      <?php endforeach; ?>
    </tbody>
  </table>
</section>
/config/bootstrap_cli.php
...
// ▼下記を追加
Configure::write('Bake.theme', 'MyBakeTheme');

これで bake コマンドを実行すると、下記ファイルが生成されます。

> cd /path/to/cakephp4
> bin/cake bake template articles

Baking `index` view template file...

Creating file \path\to\cakephp4\templates\Articles\index.php
Wrote `\path\to\cakephp4\templates\Articles\index.php`
/templates/Articles/index.php
<section>
  <h1><?= __('Articles') ?></h1>

  <table>
    <thead>
      <tr>
        <th><?= __('id') ?></th>
        <th><?= __('title') ?></th>
        <th><?= __('body') ?></th>
        <th><?= __('created') ?></th>
        <th><?= __('modified') ?></th>
      </tr>
    </thead>
    <tbody>
      <?php foreach ($articles as $article): ?>
        <tr>
          <td><?= h($article->id) ?></td>
          <td><?= h($article->title) ?></td>
          <td><?= h($article->body) ?></td>
          <td><?= h($article->created) ?></td>
          <td><?= h($article->modified) ?></td>
        </tr>
      <?php endforeach; ?>
    </tbody>
  </table>
</section>

同様に、add アクション用テンプレートの Bake テンプレートは Template/add.twig、コントローラの Bake テンプレートは Controller/controller.twig に作ります。

/templates/articles/add.php テンプレートを Bake するためには、ArticlesController.php に add アクションを追加する必要があります。

Bake コマンド実行時に、自作した Bake テンプレートがないものについては、CakePHP 標準の Bake テンプレートが用いられます。

3. 独自 Bake テンプレート作りのコツ

3-1. CakePHP 4 標準の Bake テンプレートを参照

独自 Bake テンプレートの作成では、やはり CakePHP 4 標準の Bake テンプレートが参考になります。

標準の Bake テンプレートは下記フォルダの中にあります。

/path/to/cakephp4/vendor/cakephp/bake/templates/bake

3-2. デバッグ活用

既存の Bake テンプレートにある変数をダンプしたい時があると思います。Twig 形式では、変数に「| debug」 をつけることで debug() の結果を得ることが出来ます。

例えば、上記 /plugin/MyBakeTheme/templates/bake/Template/index.twig の1行目に下記を追加して bake し、生成された index.php を確認してみてください。

/plugins/MyBakeTheme/templates/bake/Template/index.twig
{{ fields|debug }}
...

標準 Bake テンプレートと debug を組み合わせることで、独自のテンプレートが一通り作れると思います。

3-3. インデントを直す

Bake テンプレートは、生成するファイルに影響を与えないようにするために、twig 用タグのインデントが無くなっています。特にネストが深い場合には、分析や作成の時点では適切にインデントをつけて、完成したらそれらをすべて削除するのがいいのではないかと思います。

例えば下記のような場合です

// Before
{% for field in fields %}
{% set isKey = false %}
{% if associations.BelongsTo %}
{% for alias, details in associations.BelongsTo %}
{% if field == details.foreignKey %}
{% set isKey = true %}

// After (完成したらまた上記のように戻す)
{% for field in fields %}
  {% set isKey = false %}
  {% if associations.BelongsTo %}
    {% for alias, details in associations.BelongsTo %}
      {% if field == details.foreignKey %}
        {% set isKey = true %}
        ...

4. おわりに

Bake テンプレートの自作は twig の知識も必要になるため、学習コストが高く、敷居がやや高めだとは思います。

しかし、個人的にはその価値があると思います。特に似たような機能、似たような画面を何度も実装する場合には効果が大きくなりますので、是非チャレンジしてみてください。