九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、ここのところLaravel
の記事から遠ざかってしまったので、この辺で前から一度作ってみたかった「ちょっとした機能」をつくってみることにしました。
それは、この間公開した「完全な手順!Laravelバリデーション前にデータを加工する方法」が元ネタになっているのですが、簡単にどういう機能かと言うと、
送信されてきた値をaccessorのように簡単に加工できるようにする
というものです。
Laravel
をよく使う方ならご存知だと思うのですが、accessor
とはデータベースの値を簡単に加工できる強力な機能で、例えば名字と名前を結合したfull_name
という値を取得するには、モデル内にget****Attribute()
というメソッドを追加することで有効になります。
<?php namespace App; // 省略 class User extends Authenticatable { // 省略 // Accessor public function getFullNameAttribute() { return $this->last_name .' '. $this->first_name; } }
使い方はこうです。
$user = \App\User::find(1); echo $user->full_name; // 元々存在していない "full_name" が使える!
※ つまり、毎回結合するコードを書かなくてもいいわけですね。
そして、ずっと前からこの機能がFormRequest
にもほしいなと考えていたんです。元ネタの記事ではall()
を上書きする形で実装しましたが、保守管理はacessor
形式の方がずっといいと思ったんです。
そこで!
今回は、FormRequest
内でaccessor
が使えるようにする方法をご紹介します。(いつも以上に簡単にできます)
ぜひ皆さんのお役に立てると嬉しいです😊✨
開発環境: Laravel 5.7
目次
やりたいこと
具体的に実装したい機能は次のとおりです。
- FormRequest のデータを加工して取得できる
- 加工したデータは、通常通りバリデーションに使える
- 同じく、加工データは $request->xxxxx;としてアクセスできる
では実行してみましょう!
まずは、独自のFormRequestをつくる
今回はテストとして、TestRequest
をつくって説明を進めていきます。
では、以下のコマンドを実行してください。
php artisan make:request TestRequest
すると、app/Http/Requests/TestRequest.php
というファイルが作成されるので、このファイルを開いておいてください。
accessor が使えるようにトレイトを作成する
次にTestRequest.php
でaccessor
機能が使えるように独自の「トレイト」を作ります
※ トレイトというのは、ある特定の機能をPHP
クラスに追加するもので、Vue
を使う人なら「ミックスイン」というイメージが分かりやすいかと思います。
では、app/FormRequestAppendable.php
というファイルをつくって中身を以下のようにしてください。
<?php namespace App; use Illuminate\Support\Str; trait FormRequestAppendable { public function all($keys = null) { $results = parent::all($keys); foreach($this->appends as $append) { $method = Str::camel('get_'. $append .'_attribute'); if(method_exists($this, $method)) { $results[$append] = $this->{$method}($results); } } return $results; } }
この中では、FormRequest
のall()
を上書きしています。
流れとしては、初期値をparent::all()
から取得し、そこに$appends
で指定されたaccessor
の値を追加するようにしています。
使い方
使い方としてはFormRequest
に$appends
というメンバー変数を作り、それに該当するaccessor
を独自につくるだけでOKです。
例えば、「時」「分」を結合したtime
という値をつくるにはこのようにします。(太字が追加した部分です)
<?php namespace App\Http\Requests; use App\FormRequestAppendable; use Illuminate\Foundation\Http\FormRequest; class TestRequest extends FormRequest { use FormRequestAppendable; protected $appends = ['time']; // 省略 // Accessor public function getTimeAttribute($values) { if($this->filled('hours', 'minutes')) { return $values['hours'] .':'. $values['minutes']; } } }
バリデーションにつかえる
先ほどaccessor
機能でつくった値time
は、通常のデータと同じようにバリデーションにも使えます。
class TestRequest extends FormRequest { // 省略 public function rules() { return [ 'time' => 'required|date_format:H:i' ]; }
データ取得もできます
例えば、バリデーションが成功してコントローラーでtime
の値を取得するのもいつもと同じ使い方でOKです。
class HomeController extends Controller { public function store(TestRequest $request) { echo $request->time; // 時・分を結合したデータ }
元データの加工にも使える
今回のトレイトは、新しい値をつくるためだけのものではなく、元データの加工にも使うことができます。
例えば、name_kana
という「名前のかな」を入力する場合で、これをカタカナで統一したい場合は以下のようにします。
<?php // 省略 class TestRequest extends FormRequest { use FormRequestAppendable; protected $appends = ['name_kana']; // 省略 // Accessor public function getNameKanaAttribute($values) { return mb_convert_kana($values['name_kana'], 'C'); // カタカナで統一 } }
お疲れ様でした😊✨
パッケージ化しました
はじめは、独自にトレイトをつくって実装すればいいかなとも思ったんですが、毎回このトレイトをコピペするのはめんどうですので、composer
パッケージとして公開しました。(MITライセンスですので、自由に使ってください)
GitHub: SUKOHI/FormRequestAppendable
インストールは以下のコマンドになります。
composer require sukohi/form-request-appendable:1.*
なお、このパッケージでaccessor
機能を使う場合は、今回説明したものとはネームスペースが違っているので気をつけてください。(その他の使い方は全く一緒です)
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Sukohi\FormRequestAppendable\FormRequestAppendable; class TestRequest extends FormRequest { // 省略
おわりに
ということで、今回はaccessor
機能をFormRequest
内でも使えるようにしてみました。これで保守管理もより良くなれば嬉しいです。
なお、今回のaccessor
で使えるケースをまとめてみました。
こちらも参考にしてみてくださいね。
- 名字と名前を結合して “full_name” をつくる
- 郵便番号の前半と後半をつなげる
- mb_convert_kana()を使って全角の英数字を半角に統一する
- 日付の “/” を “-” に置き換える
- カナカナで統一する
などなど
ぜひ皆さんも使ってみてくださいね。
ではでは〜!
「久しぶりに独自パッケージを公開しました😊」