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

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

新規登録して質問してみよう
ただいま回答率
85.49%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

1回答

660閲覧

【Laravel】1回目のフォーム送信にのみバリデーションが機能しない

hiroaki510

総合スコア16

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

0クリップ

投稿2018/07/05 09:37

編集2018/07/07 04:37

前提・実現したいこと

株のポートフォリオを管理できるwebアプリを作っています。
ユーザー入力に対してバリデーションを実装したいです。

OS mac10.13
PHP7.1.14
laravel 5.6

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

https://teratail.com/questions/133952
以前の質問後に私なりに色々と学び、ある程度バリデーションの実装ができました。
今回質問したいのは、1回目のフォーム送信にだけバリデーションが機能しないということです。

作成しているアプリでは、存在しない証券コード(上場企業のidのようなものです)をデータベースに記録できないようにしたいです。
ですが、1回目のフォーム送信ではそのまま記録出来てしまいます。
↓画像で言うと証券コード9999というのは存在しませんが、記録出来てしまいます。

しかし、2回目以降はきちんとバリデーション出来ます。(証券コード1234も存在しません)

該当のソースコード

バリデーションの実装はフォームリクエストを利用しています。

//App\Http\Requests\addStockRequest //今回の質問に関わらないと思われるコードは省略 class addStockRequest extends FormRequest { public function authorize(){ if($this->path() == 'make/add'){ return true; }else{ return false; } } public function rules(){ return [ 'stock_code' => 'filled|digits:4|integer', 'codeDataBaseCheck' => 'different:stock_code', 'codeExistCheck' => 'numeric' ]; } public function messages(){ return[ 'stock_code.filled' => '入力してください!', 'stock_code.digits' => '4桁の数字を入力してください!', 'stock_code.integer' => '整数を(半角で)入力してください!', 'codeDataBaseCheck.different' => 'その証券コードは既に入力されています!', 'codeExistCheck.numeric' => 'その証券コードは読み取れません!' ]; } }

ビューのコードも載せます。
証券コードが存在するかどうかは、グーグルファイナンスの非公式APIを利用して判別しています。
簡潔に言うと、証券コードを引数にして、その株価が返り値となるような関数を作成しています。
もし存在しない証券コードを引数に渡すと、'DATA='という文字列が返るようになっています。

//resources\views <form method="POST" action="/make/add"> {{ csrf_field() }} @if($errors->has('codeExistCheck')) <tr><td>{{$errors->first('codeExistCheck')}}</td></tr> @elseif($errors->has('codeDataBaseCheck')) <tr><td>{{$errors->first('codeDataBaseCheck')}}</td></tr> @elseif($errors->has('stock_code')) <tr><td>{{$errors->first('stock_code')}}</td></tr> @endif <tr><th>証券コード: </th><td><input type="text" name="stock_code" value="{{old('stock_code')}}"></td></tr> //省略 //以下、@endphpまでグーグルファイナンスのAPIを利用した関数を作成しています @php function getStockPrice($code){ $url = "https://www.google.com/finance/getprices?&x=TYO&i=1800&p=2d&f=c&q=$code"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $html = curl_exec($ch); curl_close($ch); $stockPrice = explode("\n", $html); return current(array_slice($stockPrice, -2, 1, true)); } @endphp //$itemsはユーザーテーブルと株に関するテーブルがリレーションされたモデルクラスが代入されています @foreach($items as $item) <input type="hidden" name="codeDataBaseCheck" value="{{$item->stock_code}}"> <input type="hidden" name="codeExistCheck" value="{{getStockPrice($item->stock_code)}}"> @endforeach </form>

試したこと

原因が全くわからず、何から試したら良いのかわからない状況です。
他に載せた方が良いソースコードがあれば教えてください。

7/7追記

別の問題が発生したので追記いたします。
複数の情報をフォーム送信すると、直前のデータに対するバリデーションしか機能しません。
↓の画像で言うとKDDIの証券コードである9433を入力しようとするとバリデーションが機能し、「その証券コードは既に入力されています!」と表示されます。
しかし、それ以外の2162や3475は入力できてしまいます。
イメージ説明
色々と調べると、バリデーションルールにdifferentにしているのが間違いだと思いました。
参考URL -> https://qiita.com/fagai/items/9904409d3703ef6f79a2
(自分でもcodeDataBaseCheckって書いてますしね(^_^;)。データベースを利用したバリデーションルールを設定しないといけないですよね)
上記のページを参考にしながら、修正していきたいと思います。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

自己解決しました(追記の箇所も含む)

どうしても1回目のフォーム送信のみバリデーションされないので、カスタムバリデータしました。
まず、Validatorクラスを作成しました。

// App\Http\Validators\PortfolioValidator class PortfolioValidator extends Validator { public function validateGetStockPrice($attribute,$value,$parameters){ function getStockPrice($code){ $url = "https://www.google.com/finance/getprices?&x=TYO&i=1800&p=2d&f=c&q=$code"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $html = curl_exec($ch); curl_close($ch); $stockPrice = explode("\n", $html); return current(array_slice($stockPrice, -2, 1, true)); } // 'DATA='をintval()すると0になるので、以下のif文でバリデーションする。 // 0ならエラーが出るようにしました。 if (intval(getStockPrice($value)) == 0) { return false; }else{ return true; } } }

そのあと、Validatorを組み込むためにサービスプロバイダを利用します。

// App\Providers\ValidatorServiceProvider public function boot() { $validator = $this->app['validator']; $validator->resolver(function($translator,$data,$rules,$messages){ return new PortfolioValidator($translator,$data,$rules,$messages); }); }

カスタムバリデータをフォームリクエストで利用します。

//App\Http\Requests\addStockRequest public function rules(){ return [ 'stock_code' => [ // App\Http\Validators\PortfolioValidatorで定義されたvalidateGetStockPriceはget_stock_priceと名前が変わります 'get_stock_price', ], public function messages(){ return [ 'stock_code.get_stock_price' => 'その証券コードは読み取れません!',      ],

ビューも修正しました。

php

1 // resources\views 2 3<form method="POST" action="/make/add"> 4 {{ csrf_field() }} 5 @if($errors->has('codeDataBaseCheck')) 6 <tr><td>{{$errors->first('codeDataBaseCheck')}}</td></tr> 7 @elseif($errors->has('stock_code')) 8 <tr><td>{{$errors->first('stock_code')}}</td></tr> 9 @endif 10 11 <tr><th>証券コード: </th><td><input type="text" name="stock_code" value="{{old('stock_code')}}"></td></tr> 12 13 //省略 14 15 16//$itemsはユーザーテーブルと株に関するテーブルがリレーションされたモデルクラスが代入されています 17 @foreach($items as $item) 18 <input type="hidden" name="codeDataBaseCheck" value="{{$item->stock_code}}"> 19 @endforeach 20 21 </form>

これで無事1回目のフォーム送信もバリデーション出来ました。

以下、追記した箇所の自己解決法
データベースを利用したバリデーションルールを利用しなければいけなかったので、フォームリクエストを以下のように修正しました。

public function rules(){ return [ 'stock_code' => [ 'get_stock_price', // stock_codeカラムに存在していて、かつuser_idが同じものはバリデーションされるようにしました。 Rule::unique('stocks')->where(function ($query) { return $query->where('user_id', $this->user()->id); }), ], public function messages(){ return [ 'stock_code.get_stock_price' => 'その証券コードは読み取れません!', 'stock_code.unique' => 'その証券コードは既に入力されています!', ],

これに合わせて、ビューの方も変更しました。

php

1// resources\views 2 3<form method="POST" action="/make/add"> 4 {{ csrf_field() }} 5 @if($errors->has('stock_code')) 6 <tr><td>{{$errors->first('stock_code')}}</td></tr> 7 @endif 8 9 <tr><th>証券コード: </th><td><input type="text" name="stock_code" value="{{old('stock_code')}}"></td></tr> 10 11 //省略 12 13 14 </form>

これで無事、全てのデータを参照するバリデーションが組めました。
元々のコードと比べると、かなりスッキリ出来ました。

投稿2018/07/07 13:44

hiroaki510

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問