[CakePHP4]検索フォームの実装が面倒なのでモデルのないフォームで実装する

[CakePHP4]検索フォームの実装が面倒なのでモデルのないフォームで実装する
2023年10月02日2023年10月10日

Webアプリで必要不可欠な検索フォーム。項目を入力してレコードの絞り込みができる機能ですが、実装が面倒でもあります。

CakePHPのモデルのないフォームで実装する方法を紹介します。

検索フォームもデフォルト値を入れるのが面倒

CakePHPの場合、Formヘルパーを使えばHTML出力は簡単にできますが、検索フォームは絞り込みをおこなった際のvalue値を入れたりするのが面倒だったりします。

<?php echo ($this->Form->create(null, ['type' => 'get', 'class' => 'form-horizontal'])) ?>
<table class="table table-bordered table-sm ">
	<tbody>
		<tr>
			<td class="w-25">タイトル</td>
			<td><?= $this->Form->control('title', ['type' => 'text', 'label' => false, 'class' => 'form-control', 'value' => $this->request->getQuery('title')]); ?></td>
		</tr>
		<tr>
			<td>ステータス</td>
			<td>
				<div class="d-inline-flex"><?= $this->Form->control('status', ['type' => 'radio', 'label' => false, 'options' => ArticleConst::STATUS_LIST, 'empty' => 'すべて', 'class' => 'form-check-label', 'value' => $this->request->getQuery('status')]); ?></div>
			</td>
		</tr>
	</tbody>
</table>
<div class="row">
	<div class="col-md-4 offset-md-4">
		<?= $this->Form->button('検索', ['type' => 'submit', 'class' => 'btn btn-primary', 'escape' => false]); ?>
	</div>
</div>

<?php echo $this->Form->hidden('limit', ['value' => $this->Paginator->param("perPage")]); ?>
<?php echo ($this->Form->end()) ?>
getパラメーターから値を取得して入れないといけない。
$this->request->getQuery('title')

もっとシンプルにしたい。

モデルのないフォームを使おう

通常のFormであれば、Modelと紐づいている必要がありますが、Modelを使用したくない機能を実現するために用意されているモデルのないフォームを使うことで実装を簡素化することができます。

モデルのないフォーム
参考:https://book.cakephp.org/4/ja/core-libraries/form.html

モデルのないフォームは主にお問合せフォームでよく使われますが、今回は検索フォームで使います。

検索フォーム用のFormクラスを作成します。

入力値の不正をバリデーションで弾くことも可能ですが、今回は入力値チェックはおこないません。

~/src/Form/Admin/ArticleSearchForm.php
<?php

namespace App\Form\Admin;

use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;

class ArticleSearchForm extends Form
{

    protected function _buildSchema(Schema $schema): Schema
    {
        return $schema->addField('title', [
            'type' => 'string'
        ])
            ->addField('status', [
                'type' => 'string'
            ]);
    }

    public function validationDefault(Validator $validator): Validator
    {
        // ここに各項目のバリデーションを定義できます。

        return $validator;
    }

    protected function _execute(array $data): bool
    {
        return true;
    }
}

コントローラーに下記を記述します。

use App\Form\Admin\ArticleSearchForm;


$articleSearchForm = new ArticleSearchForm();
$articleSearchForm->execute($this->request->getQuery());

$this->set(compact('articleSearchForm'));

バリデーションを行いたい場合は下記のように記述します。

$articleSearchForm = new ArticleSearchForm();
if($articleSearchForm->execute($this->getRequest()->getQuery())){
    // 正常
}else{
    // バリデーションエラー
}
$this->set(compact('articleSearchForm'));

View側(template)は下記のように記述します。

<?php echo ($this->Form->create($articleSearchForm, ['type' => 'get', 'class' => 'form-horizontal'])) ?>
<table class="table table-bordered table-sm ">
	<tbody>
		<tr>
			<td class="w-25">タイトル</td>
			<td><?= $this->Form->control('title', ['type' => 'text', 'label' => false, 'class' => 'form-control']); ?></td>
		</tr>
		<tr>
			<td>ステータス</td>
			<td>
				<div class="d-inline-flex"><?= $this->Form->control('status', ['type' => 'radio', 'label' => false, 'options' => ArticleConst::STATUS_LIST, 'empty' => 'すべて', 'class' => 'form-check-label', 'default' => '']); ?></div>
			</td>
		</tr>
	</tbody>
</table>
<div class="row">
	<div class="col-md-4 offset-md-4">
		<?= $this->Form->button('検索', ['type' => 'submit', 'class' => 'btn btn-primary', 'escape' => false]); ?>
	</div>
</div>
<?php echo ($this->Form->end()) ?>

$this->Form->create($articleSearchForm)のようにFormクラスを渡すことで、検索された値を各Inputの入力値に自動セットできるようになります。

バリデーションもおこないたい場合

検索フォームでもバリデーションをおこなう場合は、Formクラスにバリデーションの条件を追加します。

~/src/Form/Admin/ArticleSearchForm.php
public function validationDefault(Validator $validator): Validator
{
    return $validator->allowEmptyString('title')->maxLength('title', 10,'10文字以内で入力してください。');
}

バリデーションに引っかかった場合は下記のように表示することができます。

検索フォーム

まとめ

モデルのないフォームで検索フォームを実装する方法を紹介しました。

検索フォームの項目数が少ない場合はメリット感が少ないですが、項目数が多い場合は威力を発揮してくれます。

また配列で渡すところを文字列で渡すと内部エラーが発生したりするかと思いますが、フォーマットを厳正にしたい場合はバリデーションで弾くことができます。

コメント

コメントを残す

お名前(任意)
コメント:新規