質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.78%

Laravel5 配列を利用した連続バリデーションに関して

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,382

YATORI

score 13

前提・実現したいこと

フォームから受け取った配列のバリデーションをしたい。

仕様

・2つのセレクトボックスをもつフォームを@forループで複数行作成。
   渡ってくるリクエストパラメータは下記のようなイメージ
    ==============================
        array(2) {
          ["name_a"]=>
          array(5) {
            [0] => string(0) ""
            [1] => string(1) "1"
            [2] => string(1) "2"
            [3] => string(1) "3"
            [4] => string(0) ""
          }
          ["name_b"]=>
          array(5) {
            [0] => string(0) ""
            [1] => string(1) "1"
            [2] => string(0) ""
            [3] => string(0) ""
            [4] => string(0) ""
          }
    ==============================

・カスタムバリデーション内で、選択されたセレクトボックスが同一かどうか確認。
    →同一の場合バリデーションエラーとしたい

・セレクトボックスで選択されたものに対し全てバリデーションチェックし、結果をviewに返す。

ソースコード

リクエストされるView

// test.blade.php
// ~中略~
    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
    <br>
   {!! Form::open() !!}
        <div class="form-inline">
            @for ($i = 0; $i < 5; $i++)
                <?php $n = $i+1 ?>
                {{ "#$n : " }}
                <div class="form-group">
                    {!! Form::select("name_a[$i]", $namelist, null, ['class' => 'form-control', 'placeholder' => "名称A"]) !!}
                </div>
                &nbsp;―&nbsp;
                <div class="form-group>
                    {!! Form::select("name_b[$i]", $namelist, null, ['class' => 'form-control', 'placeholder' => "名称B"]) !!}
                </div>
                <br>
                <br>
            @endfor
        </div>
        <div class="form-group">
            {!! Form::submit(' 登 録 ', ['class' => 'btn btn-primary']) !!}
        </div>
    {!! Form::close() !!}
// ~中略~

カスタムバリデーション

<?php
namespace app\Services;

class CustomValidator extends \Illuminate\Validation\Validator
{
    public function validateBoo()
    {

        if($this->data['name_a'] == $this->data['name_b']){
            return false;
        }
        return true;

    }

}

コントローラー

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;

class GameResultController extends Controller
{
// ~中略~

    public function store(Request $request)
    {
        $formlist = $request->all();

        foreach ($request->get('name_a') as $key => $value) {
            $i= $key+1;

            if (("" !== $formlist ["name_a"][$key]) && ("" !== is_null($formlist ["name_b"][$key]))
            {

                $rules['name_a.'.$key] = 'boo';
                $messages['name_a.'.$key.'.boo'] = '#'.$i.' :同一の名称が選択されています。';

            }
        }

        /*** バリデーション実行 ***/
        $this->validate($request,$rules,$messages);

        // ~中略~

    }
}

発生している問題・エラーメッセージ

連続するバリデーション内でエラーと判定されなかったものが存在する場合に、
エラーとなるべき項目が無視されて後続が処理される。

・以下のように連続してバリデーションエラーとなる場合は、
 正常にviewにエラーメッセージが表示されます。
  (配列0~3までがエラーとなり、4つのエラーメッセージが表示されます)

array(2) {
  ["name_a"]=>
  array(5) {
    [0] => string(1) "1"
    [1] => string(1) "2"
    [2] => string(1) "3"
    [3] => string(1) "4"
    [4] => string(0) ""
  }
  ["name_b"]=>
  array(5) {
    [0] => string(1) "1"
    [1] => string(1) "2"
    [2] => string(1) "3"
    [3] => string(1) "4"
    [4] => string(0) ""
  }


・以下のような場合は、途中のエラーとなるべき箇所が無視されて後続を処理してしまいます。

array(2) {
  ["name_a"]=>
  array(5) {
    [0] => string(1) "1"
    [1] => string(1) "2"
    [2] => string(1) "3"
    [3] => string(1) "4"
    [4] => string(0) ""
  }
  ["name_b"]=>
  array(5) {
    [0] => string(1) "1"
    [1] => string(1) "2"
    [2] => string(1) "2"
    [3] => string(1) "4"
    [4] => string(0) ""
  }


そもそも、やり方自体が違う等あるかもしれません。
どなたか、お力添え頂ければ幸いです。

補足情報(言語/FW/ツール等のバージョンなど)

・XAMPP
・Laravel 5.2.7
・PHP 7.0.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

まず、いくつかおかしい所を回答とさせていただきます。

1.修正されたControllerで、is_Nullになっていますが大丈夫でしょうか?(Nは小文字では?)
2.validateの内容がそもそもおかしいです。$this->dataで指定した場合はValidatorのdataを参照しているので今の状態だと、name_a配列 == name_b配列をkeyの回数分やっているように見えます。
正常に出ているパターンは、配列の内容がどちらも一緒だからfalseが3回となり、空文字の場合は対象のvalidateが実行されてないので表示されないのでしょう。

これを解決するためにはvalidateBooのメソッドを変更する必要があります。
例えばですが、

public function validateBoo($attribute, $value, $parameters)
{
    if($value === $this->data['name_b'][$parameters[0]]){
        return false;
    }
    return true;
}


として、ルールを

$rules['name_a.'.$key] = 'boo:'. $key;


とすることで、パラメータとして$keyが渡せるので判定可能になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/08 22:07

    お早い回答感謝いたします!

    まず、「is_Null」はご指摘の通り間違いです。正しくは「is_null」です。
    (なぜかPhpStormで怒られずにそのまま使えていました・・・)

    validateをご指摘の内容で修正したところ、無事想定通りの判定が行われました。
    確かに、バリデータの方で配列を意識できていませんでしたね・・・
    なるほど、$parameters をうまく使えばいいのですね。

    回答ありがとうございました!!

    キャンセル

  • 2016/02/09 23:53

    回答に関連した部分の編集を行ったのでこちらにもコメントをしておきます。
    Controllerのif文内の「is_null」に関してですが、
    ""(ダブルクォート)だと空判定してもらえず、毎回全ループしていたことが発覚。
    評価方法を変更しました。

    解決済みでしたが、万が一参考にされる方がいらっしゃる可能性も加味して編集させていただきました。

    キャンセル

0

申し訳ありません。
いったん解決済みとして、凍結させてください。
ソースを確認したところ、初歩的なミスを発見しました。

修正して確認後、再度書き込みます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/08 14:27

    コントローラー内のIF文が間違っていたものを修正しました。
    バリデートとは関係ない部分だったので、症状は解決しないままです。

    引き続き回答を募集させていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る