親子関係にあるテーブルを、スレッド状のデータとして取得したい場合があると思います。
今回は、CakePHPのfinderを利用して、スレッド状のデータを検索するサンプルを説明いたします。
準備
最初に、スレッド状のデータを検索するためのデータを準備します。
各テーブルの作成、テストデータの登録、動作確認用のコントローラー、テンプレートを作成していきます。
users テーブルの作成
Users、Comment用のモデルを新しく作ります。
今回の例では、中間テーブル用のモデルは作成しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
[hoge@test app]$ bin/cake bake model users One moment while associations are detected. Baking table class for Users... Creating file /home/hoge.com/app/src/Model/Table/UsersTable.php Wrote `/home/hoge.com/app/src/Model/Table/UsersTable.php` Deleted `/home/hoge.com/app/src/Model/Table/.gitkeep` Baking entity class for User... Creating file /home/hoge.com/app/src/Model/Entity/User.php Wrote `/home/hoge.com/app/src/Model/Entity/User.php` Deleted `/home/hoge.com/app/src/Model/Entity/.gitkeep` Baking test fixture for Users... Creating file /home/hoge.com/app/tests/Fixture/UsersFixture.php Wrote `/home/hoge.com/app/tests/Fixture/UsersFixture.php` Deleted `/home/hoge.com/app/tests/Fixture/.gitkeep` Bake is detecting possible fixtures... Baking test case for App\Model\Table\UsersTable ... Creating file /home/hoge.com/app/tests/TestCase/Model/Table/UsersTableTest.php Wrote `/home/hoge.com/app/tests/TestCase/Model/Table/UsersTableTest.php` Done [hoge@test app]$ |
comments テーブルの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[hoge@test app]$ bin/cake bake model comments One moment while associations are detected. Baking table class for Comments... Creating file /home/hoge.com/app/src/Model/Table/CommentsTable.php Wrote `/home/hoge.com/app/src/Model/Table/CommentsTable.php` Baking entity class for Comment... Creating file /home/hoge.com/app/src/Model/Entity/Comment.php Wrote `/home/hoge.com/app/src/Model/Entity/Comment.php` Baking test fixture for Comments... Creating file /home/hoge.com/app/tests/Fixture/CommentsFixture.php Wrote `/home/hoge.com/app/tests/Fixture/CommentsFixture.php` Bake is detecting possible fixtures... Baking test case for App\Model\Table\CommentsTable ... Creating file /home/hoge.com/app/tests/TestCase/Model/Table/CommentsTableTest.php Wrote `/home/hoge.com/app/tests/TestCase/Model/Table/CommentsTableTest.php` Done [hoge@test app]$ |
データ確認
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
MySQL [sample_db]> select * from users; +----+-------------+-------------+--------+----------+----------------+------------+---------------------+---------------------+ | id | name | kana | gender | birthday | email | password | created | modified | +----+-------------+-------------+--------+----------+----------------+------------+---------------------+---------------------+ | 1 | user_name_1 | user_kana_1 | NULL | NULL | user1@test.com | 1234567890 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 2 | user_name_2 | user_kana_2 | NULL | NULL | user2@test.com | 1234567890 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 3 | user_name_3 | user_kana_3 | NULL | NULL | user3@test.com | 1234567890 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | +----+-------------+-------------+--------+----------+----------------+------------+---------------------+---------------------+ 3 rows in set (0.00 sec) MySQL [sample_db]> select * from comments; +----+---------+-------------------+--------------------------------------------------------------------------+---------------------+---------------------+ | id | user_id | comment_parent_id | content | created | modified | +----+---------+-------------------+--------------------------------------------------------------------------+---------------------+---------------------+ | 1 | 1 | NULL | ユーザー1のコメント1 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 2 | 1 | NULL | ユーザー1のコメント2 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 3 | 1 | NULL | ユーザー1のコメント3 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 4 | 1 | 2 | ユーザー1のコメント1に対するコメント1 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 5 | 2 | NULL | ユーザー2のコメント1 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 6 | 2 | NULL | ユーザー2のコメント2 | 2021-06-14 10:00:00 | 2021-06-14 10:00:00 | | 7 | 2 | NULL | ユーザー2のコメント3 | 2021-07-01 09:02:26 | 2021-07-01 09:02:27 | | 8 | 2 | NULL | ユーザー2のコメント4 | 2021-07-01 09:02:45 | 2021-07-01 09:02:46 | | 9 | 2 | 6 | ユーザー2のコメント2に対するコメント | 2021-07-01 09:03:23 | 2021-07-01 09:03:24 | | 10 | 2 | 7 | ユーザー2のコメント3に対するコメント | 2021-07-01 09:03:51 | 2021-07-01 09:03:51 | | 11 | 3 | NULL | ユーザー3のコメント1 | 2021-07-01 09:04:04 | 2021-07-01 09:04:05 | | 12 | 3 | NULL | ユーザー3のコメント2 | 2021-07-01 09:04:32 | 2021-07-01 09:04:32 | | 13 | 2 | 10 | ユーザー2のコメント3に対するコメントのコメント | 2021-07-01 09:05:31 | 2021-07-01 09:05:31 | | 14 | 3 | 11 | ユーザー3のコメント1に対するコメント1 | 2021-07-01 09:06:17 | 2021-07-01 09:06:18 | +----+---------+-------------------+--------------------------------------------------------------------------+---------------------+---------------------+ 14 rows in set (0.00 sec) |
Controller 作成
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[hoge@test app]$ bin/cake bake controller comments Baking controller class for Comments... Creating file /home/hoge.com/app/src/Controller/CommentsController.php Wrote `/home/hoge.com/app/src/Controller/CommentsController.php` Bake is detecting possible fixtures... Baking test case for App\Controller\CommentsController ... Creating file /home/hoge.com/app/tests/TestCase/Controller/CommentsControllerTest.php Wrote `/home/hoge.com/app/tests/TestCase/Controller/CommentsControllerTest.php` Done [hoge@test app]$ |
Template 作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[hoge@test app]$ bin/cake bake template comments Baking `index` view template file... Creating file /home/hoge.com/app/templates/Comments/index.php Wrote `/home/hoge.com/app/templates/Comments/index.php` Baking `view` view template file... Creating file /home/hoge.com/app/templates/Comments/view.php Wrote `/home/hoge.com/app/templates/Comments/view.php` Baking `add` view template file... Creating file /home/hoge.com/app/templates/Comments/add.php Wrote `/home/hoge.com/app/templates/Comments/add.php` Baking `edit` view template file... Creating file /home/hoge.com/app/templates/Comments/edit.php Wrote `/home/hoge.com/app/templates/Comments/edit.php` [hoge@test app]$ |
以上で、スレッド状のデータを検索するための準備が整いました。
スレッド状のデータ検索
上記で生成した、Controllerに対して、
スレッド状のデータを検索するためのコードを追加していきます。
Controller の編集
1 2 3 4 5 6 7 8 9 10 11 12 |
public function index() { $this->paginate = [ 'contain' => ['Users'], ]; $comments = $this->paginate($this->Comments->find('threaded', [ 'parentField' => 'comment_parent_id', ])); $this->set(compact('comments')); } |
スレッド状のデータ検索では、find('threaded') finder を利用します。
find('threaded') finderは、キーフィールドを通じて一つにネストされたエンティティーを返します。
デフォルトのフィールドは、 parent_id ですが、変更することも可能です。
上記の例では、parent_id の代わりに、comment_parent_id を指定しています。
Tempalte の編集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<div class="comments index content"> <?= $this->Html->link(__('New Comment'), ['action' => 'add'], ['class' => 'button float-right']) ?> <h3><?= __('Comments') ?></h3> <div class="table-responsive"> <table> <thead> <tr> <th><?= $this->Paginator->sort('id') ?></th> <th><?= $this->Paginator->sort('user_id') ?></th> <th><?= $this->Paginator->sort('comment_parent_id') ?></th> <th><?= $this->Paginator->sort('content') ?></th> <th><?= $this->Paginator->sort('created') ?></th> <th><?= $this->Paginator->sort('modified') ?></th> </tr> </thead> <tbody> <?php foreach ($comments as $comment): ?> <tr> <td><?= $this->Number->format($comment->id) ?></td> <td><?= $comment->has('user') ? $this->Html->link($comment->user->name, ['controller' => 'Users', 'action' => 'view', $comment->user->id]) : '' ?></td> <td><?= $this->Number->format($comment->comment_parent_id) ?></td> <td><?= h($comment->content) ?></td> <td><?= h($comment->created) ?></td> <td><?= h($comment->modified) ?></td> </tr> <?php foreach ($comment->children as $ch): ?> <tr style="background-color: lightblue"> <td><?= $this->Number->format($ch->id) ?></td> <td><?= $ch->has('user') ? $this->Html->link($ch->user->name, ['controller' => 'Users', 'action' => 'view', $ch->user->id]) : '' ?></td> <td><?= $this->Number->format($ch->comment_parent_id) ?></td> <td><?= h($ch->content) ?></td> <td><?= h($ch->created) ?></td> <td><?= h($ch->modified) ?></td> </tr> <?php endforeach; ?> <?php endforeach; ?> </tbody> </table> </div> <div class="paginator"> <ul class="pagination"> <?= $this->Paginator->first('<< ' . __('first')) ?> <?= $this->Paginator->prev('< ' . __('previous')) ?> <?= $this->Paginator->numbers() ?> <?= $this->Paginator->next(__('next') . ' >') ?> <?= $this->Paginator->last(__('last') . ' >>') ?> </ul> <p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p> </div> </div> |
検索結果
スレッド状のデータ検索結果は、下記のような結果になります。
今回の表示例では、1階層までの表示なので、多階層で表示する場合には、もう少し工夫が必要ですが、
基本の考え方は、1階層の表示と同じです。
Cookbook
Cookbook
find('threaded') finder はキーフィールドを通じて一つにネストされたエンティティーを返します。 デフォルトで、このフィールドは、 parent_id です。この finder は、'隣接リスト' スタイルの テーブルに保存されたデータにアクセスすることができます。与えられた parent_id にマッチする すべてのエンティティーは、 children 属性の下に配置されます。