LoginSignup
15
11

More than 5 years have passed since last update.

CakePHP3で一覧画面表示の実装を共通化する方法

Last updated at Posted at 2016-04-22

CakePHP3で一覧画面表示の実装を共通化する方法

index.ctpでよく見る一覧画面の実装

例)ユーザーの一覧画面

<table>
<thead>
  <tr>
    <th><?= $this->Paginator->sort('id') ?></th>
    <th><?= $this->Paginator->sort('mame') ?></th>
    <th><?= $this->Paginator->sort('sex') ?></th>
    <th><?= $this->Paginator->sort('age') ?></th>
    <th><?= $this->Paginator->sort('mail') ?></th>
    <th><?= $this->Paginator->sort('tel') ?></th>
    <th><?= __('Actions') ?></th>
  </tr>
</thead>
<tbody>
<?php foreach ($users as $user): ?>
  <tr>
    <td><?= $user->id ?></td>
    <td><?= $user->name ?></td>
    <td><?= $user->sex ?></td>
    <td><?= $user->age ?></td>
    <td><?= $user->mail ?></td>
    <td><?= $user->tel ?></td>
    <td><?= $this->Html->link(__('Edit'), ['action' => 'edit', $user->id]) ?></td>
  </tr>
<?php endforeach; ?>
</tbody>
</table>

という感じで他のindex画面も同じように作っていくわけですが、書いていくのが面倒です・・・

Bakeで楽はできるけども、コード量が増えるということはバグが増えるということで極力書きたくないもの。

というわけで良い方法がないか考えてみました。

検討したポイントとしては3点

  1. 共通化したい
  2. <table>特に、<tr><td>タグを書きたくない
  3. 表示項目(テーブルのカラム名)をindex.ctpに書きたくない

検討した結果の実装コード

表示項目をコントローラーに記述

src/Controller/UsersController.ctp

namespace App\Controller;

use App\Controller\AppController;
use Cake\Collection\Collection;

class UsersController extends AppController
{
    /*
     * ヘッダー(この項目が一覧として表示される)
     */
    public $tableHeader = [
        'id',
        'name',
        'sex',
        'age',
        'mail',
        'tel',
    ];

    public function index()
    {
        $users = $this->paginate($this->Users);
        $this->set(compact('users'));
        $this->set('_serialize', ['users']);

        $seedHeader = new Collection($this->tableHeader);
        $this->set('seedHeader', $seedHeader);
    }

表示項目を毎回を書きたくないのでControllerに表示項目を記述してtemplate側に渡すことにする

table部分をElement化

src/Template/Elememt/default_table.ctp

  <table>
    <thead>
      <?php
      $contentsHeader = [];
      $contentsHeader[] = __('Actions');
      $contentsHeader = array_merge($contentsHeader, $seedHeader->map(function ($header) {
        return $this->Paginator->sort($header);
      })->toArray());
      ?>
      <?= $this->Html->tableHeaders($contentsHeader) ?>
    </thead>
    <tbody>
      <?php
      $contentsBody = $seedBody->map(function ($body) use ($seedHeader) {
        $row = [];
        $row[] = $this->Html->link(__('Edit'), ['controller' => $body->source(), 'action' => 'edit', $body->id]);
        $row = array_merge($row, $seedHeader->map(function ($header) use ($body) {
          return $body->{$header};
        })->toArray());
        return $row;
      })->toArray();
      ?>
      <?= $this->Html->tableCells($contentsBody); ?>
    </tbody>
  </table>

どの画面でも使えるようにしたいのでtable部分をelement化して外出し

CakePHP3から新しく入った $this->Html->tableHeaders()$this->Html->tableCells()を利用して

の中身をいい感じに生成

Element化したファイルを呼び出して使用する

src/Template/Users/index.ctp

~省略~

<?= $this->element('default_table', ['seedBody' => $users]); ?>

~省略~

こんな感じで作ってみました。

これでコード量をガッツリ減らすことができるので便利かなーと思います。

ポイント

・controller側で指定したヘッダー項目がcollection型で渡ってくるのでこれを$this->Html->tableHeaders()$this->Html->tableCells()を利用してmap()で処理しているいるところです。

これでindex.ctpに表示項目を書いていく作業から解放されます(๑˃̵ᴗ˂̵)و。

15
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11