前回、モデルについてモデルの属性はどこにかくのだ、とか書いていたが、いろいろやっている間に、フォームでチェックボックスを実現するときどうするのだろう、ということになったのでその覚え。
フォームをLaravelCollectiveというモジュールを使って実現する、っていうのをララ帳などで確認して作業していたが、私の案件では、チェックボックスをたくさんつけて、複数選択をさせる、という必要があった。ララ帳では触れていなかった(ような)ので、最初は、以下のように書いていた。
1 2 3 4 |
{!! Form::label('CHOICE1','選択肢1:') !!} {!! Form::checkbox('CHOICE1','1') !!} {!! Form::label('CHOICE2','選択肢2:') !!} {!! Form::checkbox('CHOICE2','2') !!} |
DBのほうは、booleanで指定するのもいいけど、項目数の変動が想定されるので、そのたびにマイグレーションしたくないな、と思って、選択肢を各ビットと見立て、DBには1つのカラムにOR演算した結果(合計値)を数値として入れておく、ビットでフラグを表現してカラムを1つにすることを想定した。
当初、コントローラークラスで、都度各ラベルの合算をして、とやっていたのだが、どうも腑に落ちない。なんかミューテータとか使えそうじゃないの?と思っていたけど選択肢の名前とDBに書き込む名前が違うので、そのままでは使えなさそう。
まいっか、と他の部分をいろいろ実装していたが、解決のきっかけとなったのは以外にもバリデーションだった。バリデーションをやろうとしたとき、「どれか1つ以上を選択してください」というやつをこの書き方では簡単には実現できないことに気づき、いろいろ調べることとなる。
チェックボックスや、ラジオボタンなどのグループ化をどうやってるんだろう、とかいろいろ探していたら、以下のように書いて配列で実現できるとの情報を見つけた。
1 2 3 4 |
{!! Form::label('choice[]','選択肢1:') !!} {!! Form::checkbox('choice[]','1') !!} {!! Form::label('choice[]','選択肢2:') !!} {!! Form::checkbox('choice[]','2') !!} |
こうすると、choiceという配列1つでチェックボックスの選択肢が表現できる。そして1つ以上のチェックをつけてねというバリデーションチェックは、以下のように簡単に実現できるようになった(FormRequestという機能で、Requestクラスの拡張クラスを使っています)。
1 2 3 4 5 6 |
public function rules() { return [ 'choice' => 'required', ]; } |
また、こうすると、複数のチェックボックスが1つの変数で表現できるので、ああミューテーターが使える!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class XXController extends Controller { private $CHOICE_WEIGHT = ["選択肢1" => "1", "選択肢2" => "2", "選択肢3" => "4"]; ・・・ public function getChoiceAttribute($value){ //合計値であるDBの値を要素に分解してモデルで利用する $c = []; foreach($this->CHOICE_WEIGHT as $key => $cn){ if(($this->CHOICE_WEIGHT[$key] & $value) > 0){ $c[] = $this->CHOICE_WEIGHT[$key]; } } return $c; } public function setChoiceAttribute($value){ //DB格納時は要素の合計値をDBに設定する $all = 0; foreach($value as $c){ $all += $c; } $this->attributes["choice"]=$all; } } |
こんな感じで実現できた!途中いろいろはしょっている、とにかくララ帳がすばらしいのでララ帳でわかんなかったところのみをメモとして残している。