こんにちは!!
きららファンタジアが始まりましたね!6CMKYFGHPJ
までフレンド申請お願いします!
@super_mannerです。
この記事はコネヒトアドベントカレンダーの11日目の記事です!
qiita.com
「CakePHPのModelのないフォームを使ってRequestバリデータを作ってみた話」 をします。
作ろうと思った動機
コネヒトでサーバーサイドでCakePHP3.xを使用し始めて1年が経ちました。
今でこそ、CakePHPの機能をある程度使えてきたかな?と思えるようになったのですが、使い始めた当時は以前使用していたLaravelと比べて癖があるな…という気持ちを持っていました。
当時を振り返ってみます。
「Laravelだったらこうできるのに!」と一番強く思ったのは、「入力値をバリデートをするタイミングが、Modelにバインドするタイミングである」という点でした。
Laravel他、これまで使用してきたフレームワークの多くがRequestそのものにバリデーションをかけるケースが多かったからです。
このようにControllerのレイヤーで行われるLaravelに対し、 CakePHPはModelで行っています。
もちろん、データをバインドするタイミングでチェックできていれば問題はないというのも最もだと思うのですが、 データを保存する箇所には関係ないRequestパラメータを早めに処理したいケースでは、やはりControllerで気軽にRequestパラメータをチェックしたいな、という気持ちが高まりました。
どうやって作ったのか
着想
今回私がベースにしたのは、CakePHPの「Modelのないフォーム」と呼ばれているものです。 https://book.cakephp.org/3.0/ja/core-libraries/form.html
ドキュメントにもあるように、主たる用途はお問い合わせフォーム等、データ保存を必要としないケースのFormの作成に使用される機構です。
- Requestパラメータが検知できる
- CakePHPのValidationの機構がそのまま流用できる
この2点から、フォームだけではなく通常のAPIでも使用できるValidationが作成可能では?!しかもCakePHPに乗っかる形で作れるのでは?!というノリと勢い、メンバーの後押しもあって開発してみようということになりました。
実装方法と使い方
現在実際に使用されているコードの一部を用いて説明しようと思います。
まず、Controllerではこのようにバリデーション用のFormのインスタンスを作成します。
ValidationForm
と命名しました。
<?php $rules = [ 'name' => [ 'rules' => [ 'require' => ['message' => 'お名前は必須です'], 'notBlank' => ['message' => 'お名前には空白文字以外を入力してください'] ] ], 'url' => [ 'rules' => [ 'require' => ['message' => 'URLは必須です'], 'url' => [ 'message' => 'URLの形式が正しくありません', 'option' => true ], 'custom' => [ 'message' => 'URLの形式が正しくありません', 'option' => "/:\/\/(.*).exsample.com\//", ] ] ] ]; $validationForm = new ValidationForm($rules); $validationForm->execute($this->request->getData());
見たままで何のひねりもなくて恐縮なのですが、
- パラメータ名をkeyにしてCakePHPのバリデーションルールを配列形式でわたす
- フォームのインスタンスを作成
- executeメソッドを実行
と言った3ステップで使ってもらうようにしました。本当は1行で書けるように…もっと簡単に….と思ってルールセットの書き方をよりLaravelライクにしたり等の試行錯誤はしてみたのですが、
- ルールセットとvalidation.addが乖離しないこと(参考: https://book.cakephp.org/3.0/ja/core-libraries/validation.html)
- ディレクトリ構成が本家CakePHPに準拠できること
を優先してこの書き方を選びました。 (なお、やはりルールセットを書く行数がかかるのでここは色々再考の余地があると考えております 😂)
次に、ざっくりとですが、ValidationForm
の実装内容をフローチャートでお見せしたいと思います。
流れだけでは伝わりづらい部分もあるかと思いますので、末尾に注釈を加えております。
- (※1) POSTされてきたデータが配列だった場合等、内部の条件にもvalidationをかけることができます
- (※2) https://api.cakephp.org/3.5/class-Cake.Validation.Validator.html#_addNestedMany
- (※3) https://github.com/cakephp/cakephp/blob/3.5.7/src/Form/Form.php#L107
- (※4) https://github.com/cakephp/cakephp/blob/3.5.7/src/Form/Form.php#L195 をオーバーライドして, validationに引っかかったら
_execute
を実行するようにしておきます - (※5) 本プロダクトで規定しているErrorCodeの付与等を行います
まとめ
今回この機能の実装を通して「フレームワークの機能を応用して別の使い方にしてみる」ということの面白さを体感したように思います。 作成者の意図には反していたかもしれないのですが、実際自分が普段あまりつかっていなかったForm周りの機構の再発見へとつなげることができました。 もう少し汎用的な作りにして、プラグインとして公開できればいいなと思っております!( ˘ω˘)スヤァ
明日は katsutomu さんによる記事です!!!お楽しみに 💁