[CakePHP3] 「モデルのないフォーム」の使いどころ

2020/03/01

author

masyus

CakePHP3の機能の1つにモデルのないフォームというものがあります。実際の開発で何回か使うことがありましたので、機能紹介しつつ実際の利用シーンについて紹介します。検証したCakePHPのバージョンは3.6.13、PHPは7.3です。

モデルのないフォームの特徴

以下の便利な機能があります。

  • データベースに対象となるテーブルがなくてもTableClassにて利用できるValidatorを使うことができる
  • Migrationのようにテーブルのcolumnと同様の定義を行い、フォームからの入力値を検証することができる

公式ドキュメントに記載されているサンプルコードを見てみましょう。

namespace App\Form;

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

class ContactForm extends Form
{

    protected function _buildSchema(Schema $schema)
    {
        return $schema->addField('name', 'string')
            ->addField('email', ['type' => 'string'])
            ->addField('body', ['type' => 'text']);
    }

    protected function _buildValidator(Validator $validator)
    {
        $validator->add('name', 'length', [
                'rule' => ['minLength', 10],
                'message' => '名前は必須です'
            ])->add('email', 'format', [
                'rule' => 'email',
                'message' => '有効なメールアドレスが要求されます',
            ]);

        return $validator;
    }

    protected function _execute(array $data)
    {
        // TODO メールを送信する等の処理をここに追加する
        return true;
    }
}

このようにFormクラスを構成することができます。Migrationクラス + Tableクラスのような感覚で実装できるのが良いですね。

namespace App\Controller;

use App\Controller\AppController;
use App\Form\ContactForm;

class ContactController extends AppController
{
    public function index()
    {
        $contact = new ContactForm();
        if ($this->request->is('post')) {
            if ($contact->execute($this->request->getData())) {
                $this->Flash->success('すぐにご連絡いたします。');
            } else {
                $this->Flash->error('フォーム送信に問題がありました。');
            }
        }
        $this->set('contact', $contact);
    }
}

呼び出し側のコードは上記のようになります。execute()を呼び出す際にValidationを通すことが可能です。

処理のイメージとしては入力データをnewEntity()もしくはpatchEntity()でデータ検証し、保存するまでの一連の流れを再現可能なメソッドだと思っていただくと理解しやすいかと思われます。validate()を呼び出せば入力データの検証だけさせることもできます。また、もしValidationErrorがあれば$contact->errors()でエラー内容を取得することも可能です。

モデルのないフォームの使い所

  • LP(ランディングページ)の入力フォーム
  • お問い合わせフォーム
  • API

が挙げられます。1.2.のように、「入力フォームはあるが、その入力値はデータベースへ保存せずメールで通知させるだけにしたい」 等に最適です。

3.はAPIがkey/valueで構成された値を受け取りその値をチェックしたいシーンが想定されます。HTTPメソッドがGETで返却値が1テーブルから情報を返すシンプルな構成の場合、FormよりもTableのValidatorを使うのが良さそうですが、GETの返却値が複数テーブルを跨いで情報を返したい時や、HTTPメソッドがPOST/PUT/DELETEで且つ複数テーブルのデータに追加/更新/削除をさせたい場合には威力を発揮する可能性があります。

また、入力フォームにデータベースへ保存する項目とそうでない項目がある時にも活用の余地がありそうです。例えば入力フォームにユーザーから同意を得るためのチェックボックス(データベースにはチェックされたかどうかは保存しない)が複数あるようなケースが該当します。他にも使い所はありそうです。

参考