Help us understand the problem. What is going on with this article?

CakePHPで絞り込み機能の実装

この記事は CakePHP Advent Calendar 2018 25日目の記事です。

空いていましたので、滑り込ませて頂きました。

やりたい事

ある一覧表のようなものから、絞り込み表示したい。

実装フロー

  1. マイグレーションファイルでテーブル作成
  2. マイグレーションファイルで仮データをインサート
  3. TableとEntity作成
  4. 対象テーブルにリレーションを張る
  5. Controller作成
  6. 対象テーブルから全データ取得
  7. View作成
  8. 取得データを表示
  9. フォームの作成
  10. 絞り込みボタン設置
  11. 絞り込みボタンが押されたらクエリパラメータをGETメソッドでリクエスト
  12. クエリパラメータを元にテーブルからデータを取得する際に絞り込む
  13. 絞り込まれたデータを表示

1. マイグレーションファイルでテーブル作成

今回は2つのテーブルを作成
- categories Table
- master_category_types Table

$ bin/cake migrations create CreateCategories
$ bin/cake migrations create CreateMasterCategoryType

マイグレーションファイル内のコードは下記参照

categoriesテーブル作成マイグレーションファイル

MigrationFile1
<?php
use Migrations\AbstractMigration;

class CreateCategories extends AbstractMigration
{
    public function up()
    {
        $table = $this->table('categories');
        $table->addColumn('name', 'string', [
            'null' => false
        ]);
        $table->addColumn('user_id', 'integer', [
            'null' => false
        ]);
        $table->addColumn('type_id', 'integer', [
            'null' => false
        ]);
        $table->create();
    }

    public function down()
    {
        $table = $this->table('categories');
        $table->drop();
    }
}

master_category_typesテーブル作成マイグレーションファイル

MigrationFile2
<?php
use Migrations\AbstractMigration;

class CreateMasterCategoryType extends AbstractMigration
{
    public function up()
    {
        $table = $this->table('master_category_type');
        $table->addColumn('name', 'string', [
            'null' => false
        ]);
        $table->create();
    }

    public function down()
    {
        $table = $this->table('master_category_type');
        $table->drop();
    }
}

2. マイグレーションファイルで仮データをインサート

それぞれのテーブルにデータをインサートするマイグレーションファイル作成

$ bin/cake migrations create InsertCategories
$ bin/cake migrations create InsertMasterCategoryType

categoriesテーブルにインサートするマイグレーションファイル

MigrationFile3
<?php
use Migrations\AbstractMigration;

class InsertCategories extends AbstractMigration
{
    public function up()
    {
        $table = $this->table('categories');
        $row = [
            [
                'name' => 'リンゴ',
                'user_id' => 2343,
                'type_id' => 1
            ],
            [
                'name' => 'ピアノ',
                'user_id' => 2343,
                'type_id' => 2
            ],
            [
                'name' => 'ビール',
                'user_id' => 2343,
                'type_id' => 3
            ],
            [
                'name' => 'バナナ',
                'user_id' => 2343,
                'type_id' => 1
            ],
            [
                'name' => 'ギター',
                'user_id' => 2343,
                'type_id' => 2
            ],
            [
                'name' => 'ワイン',
                'user_id' => 2343,
                'type_id' => 3
            ],
            [
                'name' => 'ブドウ',
                'user_id' => 2343,
                'type_id' => 1
            ],
            [
                'name' => 'ベース',
                'user_id' => 2343,
                'type_id' => 2
            ],
            [
                'name' => '日本酒',
                'user_id' => 2343,
                'type_id' => 3
            ],
            [
                'name' => 'ミカン',
                'user_id' => 2343,
                'type_id' => 1
            ],
        ];
        $table->insert($row);
        $table->saveData();
    }

    public function down()
    {
        $this->execute('DELETE FROM categories');
    }
}

master_category_typesテーブルにインサートするマイグレーションファイル

MigrationFile4
<?php
use Migrations\AbstractMigration;

class InsertMasterCategoryType extends AbstractMigration
{
    public function up()
    {
        $table = $this->table('master_category_type');
        $row = [
            [
                'name' => '食べ物'
            ],
            [
                'name' => '楽器'
            ],
            [
                'name' => 'お酒'
            ],
        ];
        $table->insert($row);
        $table->saveData();
    }

    public function down()
    {
        $this->execute('DELETE FROM master_category_type');
    }
}

3. TableとEntity作成

それぞれのTableクラスとEntityクラスを生成

$ bin/cake bake model categories
$ bin/cake bake model master_category_types

それぞれ中身はbake時から修正しています。

CategoriesTable
class CategoriesTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('categories');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');

        $this->belongsTo('Users', [
            'foreignKey' => 'user_id',
            'joinType' => 'INNER'
        ]);
        $this->belongsTo('MasterCategoryTypes', [
            'foreignKey' => 'type_id',
            'joinType' => 'INNER'
        ]);
    }

    public function validationDefault(Validator $validator)
    {
        return $validator;
    }
}
CategoryEntity
<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Category extends Entity
{
    protected $_accessible = [
        'name' => true,
        'user_id' => true,
        'type_id' => true,
    ];
}
MasterCategoryTypesTable
<?php
namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class MasterCategoryTypesTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('master_category_types');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');
    }

    public function validationDefault(Validator $validator)
    {
        return $validator;
    }
}
MasterCategoryTypeEntity
<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class MasterCategoryType extends Entity
{
    protected $_accessible = [
        'name' => true
    ];
}

4. 対象テーブルにリレーションを張る

CategoriesTableに以下のリレーションを張りました。

$this->belongsTo('Users', [
    'foreignKey' => 'user_id',
    'joinType' => 'INNER'
]);
$this->belongsTo('MasterCategoryTypes', [
    'foreignKey' => 'type_id',
    'joinType' => 'INNER'
]);

5. Controller作成

SampleControllerを作成

$ bin/cake bake controller sample

6. 対象テーブルから全データ取得

<?php
namespace App\Controller;

use App\Controller\AppController;

class SampleController extends AppController
{
    public function initialize()
    {
        parent::initialize();
        $this->loadModel('Categories');
        $this->loadModel('MasterCategoryTypes');
    }

    public function index()
    {
        $categories = $this->Categories
            ->find()
            ->where(['user_id' => $this->Auth->user()['id']])
            ->all();
        $this->set(compact('categories'));

        $categoryTypes = $this->MasterCategoryTypes
            ->find()
            ->all();
        $this->set(compact('categoryTypes'));

        $this->render($this->request->action);
    }
}

7. View作成

$ pwd
project/src/Template
$ mkdir Sample
$ cd Sample
$ touch index.ctp

8. 取得データを表示

<h1>欲しい物リスト</h1>
<div>
    <ul>
        <?php foreach ($categories as $category): ?>
            <li><?= $category->name ?></li>
        <?php endforeach; ?>
    </ul>
</div>

9. フォームの作成

10. 絞り込みボタン設置

11. 絞り込みボタンが押されたらクエリパラメータをGETメソッドでリクエスト

<h1>欲しい物リスト</h1>
<div>
    <?= $this->Form->create('', [
        'type' => 'get',
        'url' => [
            'controller' => 'sample',
            'action' => 'index'
        ]
    ]) ?>
    <?= $this->Form->radio('selected_type_id', $options, $attributes) ?>
    <?= $this->Form->button('絞り込む', [
        'type' => 'submit'
    ]) ?>
    <?= $this->Form->end() ?>
    <ul>
        <?php foreach ($categories as $category): ?>
            <li><?= $category->name ?></li>
        <?php endforeach; ?>
    </ul>
</div>

12. クエリパラメータを元にテーブルからデータを取得する際に絞り込む

    public function index()
    {
        $categories = $this->Categories
            ->find()
            ->where(['user_id' => $this->Auth->user()['id']]);
        if (!empty($this->request->query['selected_type_id']) && $this->request->query['selected_type_id'] != 0) {
            $categories->where([
                'type_id' => $this->request->query['selected_type_id']
            ]);
        }
        $categories->all();
        $this->set(compact('categories'));

        $categoryTypes = $this->MasterCategoryTypes
            ->find()
            ->all();
        $this->set(compact('categoryTypes'));

        $options[0] = [
            0 => '一覧'
        ];
        foreach ($categoryTypes as $categoryType) {
            $options[$categoryType->id] = [
                $categoryType->id => $categoryType->name
            ];
        }
        $this->set(compact('options'));

        $attributes = [
            'value' => 0
        ];
        if (!empty($this->request->query['selected_type_id'])) {
            $attributes['value'] = $this->request->query['selected_type_id'];
        }
        $this->set(compact('attributes'));

        $this->render($this->request->action);
    }

13. 絞り込まれたデータを表示

8. 取得データを表示

と同様のロジックの為割愛

実際の挙動

ezgif.com-video-to-gif.gif

まとめ

復習も兼ねて実装してみました。
テーブル作成からやると若干大変でしたが、理解を深められたので良かったです。

おまけ

Twitterやってます!外部のエンジニアの方ともどんどん繋がりたいと考えていますので、是非フォローして頂ければと思います!@Tatsuo96
ブログ始めました!
https://note.mu/tatsuo_iriyama

tatsuo-iriyama
Web Engineer|96'|高卒|前職:溶接工|2019-01〜ユアマイスター株式会社|
yourmystar
サービス産業のIT化プラットフォーム「ユアマイスター」と大切なものをもっと大切にするメディア「ユアマイスター スタイル」を運営するスタートアップです。
http://corp.yourmystar.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした