web-dev-qa-db-ja.com

カスタムメッセージが提供されているにもかかわらず、検証に失敗するとデフォルトのエラーメッセージが返される

期待どおりの反応が得られません。

これは、ロケーションWebサービス要求のコントローラーコードです。

<?php
namespace App\Http\Controllers;

use App\Location;
use Illuminate\Http\Request;


class LocationController extends Controller
{


    /**
     * Action method to add a location with the supplied Data
     * 
     * @param \Illuminate\Http\Request $p_oRequest Request
     * 
     * @return JSON
     */
    public function add(Request $p_oRequest)
    {

        try {

            $p_oRequest->validate(
                array(
                    'name' => 'required|alpha_num',
                    'user_id' => 'required|integer',
                ),
                array(
                    'name.required' => 'Name is required',
                    'name.string' => 'Name must be alphanumeric',
                    'user_id.required' => 'Curator User Id is required',
                    'user_id.required' => 'Curator User Id must be an integer',
                )
            );

        } catch (\Exception $ex) {

            $arrResponse = array(
                'result' => 0,
                'reason' => $ex->getMessage(),
                'data' => array(),
                'statusCode' => 404
            );

        } finally {

            return response()->json($arrResponse);

        }

    }

}

リクエストは http://mydomain/index.php/api/v1/location/add?name = @ !^

私が期待する応答理由は次のとおりです:{"result":0、 "reason": "Name must be alphanumeric"、 "data":[]、 "statusCode":404}

代わりに私が得る実際の応答は、次のとおりです。

助けてください。これは私を悩ませています。

8
user3125602

これがうまくいかない理由をついに発見しました。これは、実装コードまたはLaravelのエラーの問題ではなく、次のいずれかです。優れたPHP自明の結果を処理するためのコード。これは明らかに私がしなかった;(ii)。Laravel検証エラー応答を使用します。

Laravelの検証により、Illuminate\Validation\ValidationErrorがスローされます。信じられないかもしれませんが、これは実際にエラーメッセージをデフォルトで「指定されたデータは無効でした。」なので、\ Exceptionをキャッチして$ e-> getMessage()を取得すると、このデフォルトのエラーメッセージが(正しく)表示されます。取得する。

あなたがする必要があるのは、\ Illuminate\Validation\ValidationErrorをキャプチャすることです。 -そして、そのメソッドを使用して、そこからエラーメッセージを抽出します。

これが私が思いついた解決策です:

<?php
namespace App\Http\Controllers;

use App\Location;
use Illuminate\Http\Request;


class LocationController extends Controller
{

    /**
     * Action method to add a location with the supplied Data
     * 
     * @param \Illuminate\Http\Request $p_oRequest Request
     * 
     * @return JSON
     */
    public function add(Request $p_oRequest)
    {
        try {

            $arrValid = array(
                'name' => 'required|alpha_num',
                'user_id' => 'required|integer',
            );
            $p_oRequest->validate(
                $arrValid,
                array(
                    'name.required' => 'Name is missing',
                    'name.alpha_num' => 'Name must be alphanumeric',
                    'user_id.required' => 'User Id is missing',
                    'user_id.integer' => 'User Id must be an integer',
                )
            );

        } catch (\Illuminate\Validate\ValidationException $e ) {

            /**
             * Validation failed
             * Tell the end-user why
             */
            $arrError = $e->errors(); // Useful method - thank you Laravel
            /**
             * Compile a string of error-messages
             */
            foreach ($arrValid as $key=>$value ) {
                $arrImplode[] = implode( ', ', $arrError[$key] );
            }
            $message = implode(', ', $arrImplode);
            /**
             * Populate the respose array for the JSON
             */
            $arrResponse = array(
                'result' => 0,
                'reason' => $message,
                'data' => array(),
                'statusCode' => $e->status,
            );

        } catch (\Exception $ex) {

            $arrResponse = array(
                'result' => 0,
                'reason' => $ex->getMessage(),
                'data' => array(),
                'statusCode' => 404
            );

        } finally {

            return response()->json($arrResponse);

        }

    }

}

したがって、確かに、Laravelは正しい応答を提供し、それが缶の横で言っていたことを行いましたが、私はそれを正しく適用していませんでした。とにかく、将来の私とLaravel-seaで他の失われたPHPマリナー、ソリューションを提供します。

さらに、バグのあるコーディングを指摘してくれたMarcinに感謝します。上記のソリューションを実装した場合でも問題が発生していました。

8
user3125602

問題はおそらく、Laravelのデフォルトの例外ハンドラーが詳細な検証情報をユーザーに中継する準備ができていないことです。代わりに、ユーザーから例外の詳細を隠します。これは、検証以外の例外のセキュリティリスクを形成する可能性があるため、通常は正しいことです。

言い換えると;例外ハンドラのrender関数(/app/Exceptions/Handler.phpで実装)が検証エラーをキャッチすると、それらは一般的なアプリケーション例外として解釈され、ユーザーに再レイアウトされる一般的なエラーメッセージは常に「指定されたデータ無効でした」。

renderメソッドが\Illuminate\Validation\ValidationExceptionのインスタンスを無視することを確認してください。期待した応答が得られるはずです。

public function render($request, Exception $exception) {

    if (! $exception instanceof \Illuminate\Validation\ValidationException)) {

        // ... render code for other Exceptions here

    }

}

例外ハンドラでValidationExceptionの詳細を応答にリレーさせる別の方法は、renderメソッドで次のようにすることです。

if ($exception instanceof ValidationException && $request->expectsJson()) {
    return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);
}

バックグラウンド

Laravelは基本的にここで例外を(ab)使用しています。通常、例外はコードの(実行時)問題を示しますが、Laravelは、リクエストの検証を容易にし、ユーザーにフィードバックを提供するメカニズムとしてそれらを使用します。そのため、この場合は、例外ハンドラに例外を処理させるのは正しくありません。これはアプリケーション例外ではなく、ユーザー向けの情報です。

OPが提供する回答のコードは機能します。彼はValidationExceptionを自分でキャッチし、アプリケーションの例外ハンドラーでキャッチされないようにするためです。それが懸念の明確な組み合わせであり、ひどく長くて読めないコードを作成するので、それが望まれると思うシナリオはありません。上で示したように、ValidationExceptionsを単に無視するか、例外ハンドラーでそれらを異なる方法で処理するだけで、うまくうまくいくはずです。

7
Wilbo Baggins

私はこれを見たばかりですが、行う必要があるのは検証呼び出しを移動するだけですbefore try/catch

$p_oRequest->validate(
    [
        'name'    => 'required|alpha_num',
        'user_id' => 'required|integer',
    ],
    [
        'name.required'    => 'Name is required',
        'name.string'      => 'Name must be alphanumeric',
        'user_id.required' => 'Curator User Id is required',
        'user_id.required' => 'Curator User Id must be an integer',
    ]
);

try {

...

} catch(\Exception $e) {
    return back()->withErrors($e->getMessage())->withInput();
}

Laravelは検証例外を自動的にキャッチし、古い入力と、次のように出力できるエラーの配列を返します。

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
2
justrusty

メッセージは検証ルールである必要があるため、次の代わりに:

'name.required' => 'Name is required',
'name.string' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.required' => 'Curator User Id must be an integer',

あなたが持っているべきです:

'name.required' => 'Name is required',
'name.alpha_num' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.integer' => 'Curator User Id must be an integer',
0