CakePHP3 の Element は自分自身を再帰的に呼び出せる

階層メニューなどを作るときなんかに再帰的に作れないかなと思ってやってみたらできちゃいました。 CakePHP2 以前でも可能かもしれないです。

どこかでメニューの配列を定義します。

<?php
$menu_list = [
    ['label' => '親1', 'url' => '/parent1/', 'child' => [
        ['label' => '子1', 'url' => '/parent1/child1/'],
        ['label' => '子2', 'url' => '/parent1/child2/', 'child' => [
            ['label' => '孫1', 'url' => '/parent1/child2/grandchild1'],
            ['label' => '孫2', 'url' => '/parent1/child2/grandchild2'],
        ]],
    ]],
];
?>

src/Template/Element/menu.ctp という Element を作成します。 <?= $this->element('menu', ['menu_list' => $menu['child']]); ?> で自分自身を呼び出すことで再帰となります。

<ul>
    <?php foreach ($menu_list as $menu) : ?>
        <li>
            <?= $this->Html->link($menu['label'], $menu['url']) ?>
            
            <?php /* 子メニュー */ ?>
            <?php if (isset($menu['child'])) : ?>
                <?= $this->element('menu', ['menu_list' => $menu['child']]); // ここで再帰呼出し!!! ?>
            <?php endif ?>
        </li>
    <?php endforeach ?>
</ul>

後は好きなところで menu.ctp を呼ぶだけ

<?= $this->element('menu', ['menu_list' => $menu_list]); ?>

こんな感じの HTML が生成されます。

<ul>
  <li>
    <a href="/parent1/">親1</a>
    <ul>
      <li>
        <a href="/parent1/child1/">子1</a>
      </li>
      <li>
        <a href="/parent1/child2/">子2</a>
        <ul>
          <li>
            <a href="/parent1/child2/grandchild1">孫1</a>
          </li>
          <li>
            <a href="/parent1/child2/grandchild2">孫2</a>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>