5

I am using a Validator to validate request parameters and return helpful messages to the users of a public API. If the validator fails I return a view:

if( $validator->fails() ){
    $data = ['errors' => $validator->errors()->messages() ];
    return response()->view('errors.412', $data, 412)
                    ->header("HTTP/1.0 412 Precondition Failed", null);
} else {
    ...
}

The view...

<ul>
    @foreach( $errors as $field )
        @foreach( $field as $error )
            <li>{{ $error }}</li>
        @endforeach
    @endforeach
</ul>

Because these messages are to be consumed by developers I want them to be technical and specific. Therefore it's really annoying that Laravel automatically strips the space from my parameter keys.

For the message:

'The :attribute field is required.'

Laravel returns:

The vehicle name field is required.

...but I want the more accurate:

The vehicle_name field is required.

The only fix I have found is to add the following lines to /resources/lang/en/validation.php:

'attributes' => [
    'vehicle_name' => 'vehicle_name'
],

But that just feels backwards that I would have to provide a bunch of identical key-pair values in a language translation file just to instruct the framework to undo an unwanted behaviour.

Is there a better way?

Martin Joiner
  • 3,529
  • 2
  • 23
  • 49
  • Look into this answer https://stackoverflow.com/a/20633014/3226121 – ljubadr Oct 18 '17 at 11:44
  • This could also help [api docs](https://laravel.com/api/5.5/Illuminate/Validation/Validator.html#method___construct) `Validator::make($request->all(), [ rules ...], [ messages ... ], [ custom attributes])` Custom attributes is what you want It is repetitive, but that's one way you can do it... – ljubadr Oct 18 '17 at 12:02
  • [Validator __construct](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Validation/Validator.php#L197) – ljubadr Oct 18 '17 at 12:06
  • `$rules = [ 'access_key1' => 'nullable|string|max:200', 'access_key2' => 'numeric', 'access_key3' => 'array', ]; $keys = array_keys($rules); $customAttributes = array_combine($keys, $keys); Validator::make($request->all(), $rules, [], $customAttributes);` – ljubadr Oct 18 '17 at 12:23

3 Answers3

3

This was the cleanest way for me:

  $rules = [
    'access_key1' => 'nullable|string|max:200',       
    'access_key2' => 'numeric',       
    'access_key3' => 'array',     
  ];      

  $keys = array_keys($rules);      
  $customAttributes = array_combine($keys, $keys);      
  Validator::make($request->all(), $rules, [], $customAttributes);
digout
  • 4,041
  • 1
  • 31
  • 38
1

The answer came via a comment on a feature request that I posted on laravel/internals GitHub repo https://github.com/laravel/internals

I had gone down a wrong path in using a view to display the errors. For technical users, returning the errors in JSON is the most appropriate format and in that context the specific keys of the parameter are visible:

{
    "message": "The given data was invalid.",
    "errors": {
        "vehicle_name": [
            "The vehicle name field is required"
        ]
    }
}

So I changed my code to return JSON in the case of validation failure.

Martin Joiner
  • 3,529
  • 2
  • 23
  • 49
0

You can use your own messages for every rule:

    $data = $request->all();

    $messages= [
                'access_key.required'      => 'access_key is required, I'm technical x)',
                'access_key.max'           => 'Yooo! calm down! you exceded max characters limit'

            ];

    $rules = [
                'access_key'      => 'required|max:255',
            ];

    return Validator::make($data,$rules, $messages);

If you don't provide a message for some rule it will use default message (replacing your underscores).

So this way is like add a single flag to every rule but giving you the opportunity to rewrite the whole message and ommit whatever field you don't want to provide a specific message.

aaron0207
  • 2,293
  • 1
  • 17
  • 24
  • Given that I don't mind the default message, do you think re-supplying the whole message for each parameter makes for better code than entries in the attributes array of the language file? – Martin Joiner Oct 18 '17 at 11:27
  • You can combine them, just replace the message with `trans('file.array.message')` and write your message in every language file. Maybe I miss something but I think this would be the way. – aaron0207 Oct 18 '17 at 11:32