【CakePHP4入門】ビュー:レイアウト

CakePHP4のレイアウトを使う

Webサイトを作成していると、複数ページで共通のヘッダーやフッターやナビゲーションになっている場合があります。
もし各ページごとにこの共通箇所を重複して記述していると、実装や修正が面倒です。
CakePHPでは、こういった共通箇所を重複せずにパーツ分けして管理する方法として、以下の便利な機能が用意されています。

  • レイアウト
  • エレメント
  • セル

今回はそのうちの「レイアウト」についてみていきたいと思います。

CakePHP4のレイアウトの基本的な仕組み

サイト内のページで共通のヘッダーやフッターなどの「枠」部分をレイアウトとして作成しておくことで、
各ページでは、ページによって異なるコンテンツ部分のみを実装すれば良いことになり、共通部分の重複実装をしなくて済みます。

デフォルトでは「templates/layout/default.php」というファイルがレイアウトファイルになっています。
デフォルトのレイアウトファイルを見てみると、

<?= $this->fetch('〇〇') ?>

という記述がいくつかあることがわかります。

このfetchの記述は、各ページのテンプレートで指定した〇〇という名前のビューブロックを、レイアウトに埋め込む箇所を指します。
例えば、テンプレートファイルで、

<? $this->assign('title', 'テストタイトル'); ?>

と記述すると、レイアウトファイルの「fetch(‘title’) ?>」のところに「テストタイトル」という文字列が埋め込んだ状態になります。
titleよりも長いHTMLの場合には、次のようにブロックの指定が行えます。

<? $this->start('testblock'); ?>
テストブロック
<? $this->end('testblock'); ?>

startからendまでの間を「testblock」という名前で定義しておくことで、

<?= $this->fetch('testblock') ?>

とレイアウトに書いておけば、そこに埋め込まれることになります。

特殊なブロックに「content」というものがあります。
これは、上記のようにstart,endで括る必要がありません。
何も括られていない箇所の文末までがcontentブロックとして解釈されます。
ですので、ページのメイン部分の一番分量が多い箇所をこのcontentブロックとすることが一般的です。

defaut.phpに

<?= $this->fetch('content') ?>

という記述があると思います。そこに埋め込まれることになります。

別のレイアウトに切り替える方法

あまり多くは無いかもしれませんが、Webサイトによって異なる複数タイプのレイアウトに分かれるような場合、
ベースのレイアウトファイルを複数用意しておくと便利です。そして、このページはこのレイアウトファイル、という風に指定してあげることで、
ページに応じてレイアウトを切り替えることができます。

この切替の記述を行うのはコントローラのアクション内です。
レイアウトを指定したいページを表示するアクション内で、次のように記述します。

$this->viewBuilder()->setLayout('sample');

この場合、「templates/layout/sample.php」がレイアウトファイルになります。

全てのページのレイアウトを「default」ではなく「sample」に変えたい、という場合には、「View/AppView.php」のinitializeメソッドを以下のように変更します。

public function initialize(): void
    {
        $this->layout = 'sample';
    }

レイアウトの継承を行う方法

最後にレイアウトの継承についてみていきます。
次の①の図のように、全てのページにヘッダーフッターが付いているサイトでは、まずデフォルトのレイアウトにメイン部分以外のHTMLを記述し、
「$this->fetch(‘content’)」で各ページのメイン部分を埋め込んであげればOKです。

ところが、左カラムに固定のナビゲーションがついているページ(②)と、右カラムに固定のナビゲーションがついているページ(③)と、1カラムのみのページ(①)の3パターンに分けることができるとします。
このような場合、3つのレイアウトを個別で作成し、各ページでレイアウトを切り替えるでもよいのですが、そうすると、ヘッダーとフッター部分を3つのレイアウトファイルに記述する必要が出てきて重複が発生してしまいます。
そこで、②と③のレイアウトファイルは①を継承することで、ヘッダーフッターの記述は①に任せる、という書き方ができます。

①のファイルは通常通り「default.php」で作成し、②のファイル「leftnavilayout.php」を以下のようにします。

<? $this->extend('default'); ?>
<div id="left">
    左カラムのナビゲーション
</div>
<?= $this->fetch('content'); ?>

実際のソースコードはもっと長くなるはずですが、このレイアウトファイルを使えば、メインのcontent部分の前の

の部分が埋め込まれます。
ポイントは1行目の「extend」の部分です。「extend」は「拡張」などと言ったりしますが、プログラミングにおいては「継承」ということが多いです。

③の場合も同様に、次のように書けばOKです。

<? $this->extend('default'); ?>
<?= $this->fetch('content'); ?>
<div id="right">
    左カラムのナビゲーション
</div>

こうすることで、ヘッダーフッター部分は①のレイアウトファイルにしか記述せずに、②では左ナビゲーション部分、③では右ナビゲーション部分を追記するといった割り振りで重複実装をしなくて済むようになります。

※今回の内容はCakePHPのドキュメントを参考にしています。
参考 レイアウト