I currently have a few validation rules as follows:
\Route::post("/logError", "LogController#logError");
//In LogController
public function logError(Request $request) {
$rules = [
"name" => "required",
"message" => "required",
"level" => "in:info,debug,error"
];
$this->validate($request,$rules);
// Log the message or do whatever
});
This works fine for inputs like
[ "name"=>"Not found", "message" => "Element not found", "level" => "error" ]
[ "name"=>"Not found", "message" => "Element not found" ]`
However it throws an exception for inputs like
[ "name"=>"Not found", "message" => "Element not found", "level" => "randomgibberish" ]
My question is, since "level" is optional, is there a built-in way to validate the input and just remove optional elements that are not valid from it instead of throwing a validation exception? If not would I have to override the controller validation method to achieve this?
The validator does not modify the request input data, you need to make some sort of middleware or function in your controller that checks for the input parameters and compares them with the ones you want Laravel to check.
So yes, I think you'll need to extend the validation method, or maybe try with an helper function that does only that.
Related
Summary
Context
Sources
2.1. Unit test
2.2. FormRequest's rules method
Behaviors
3.1. Actual behavior
3.2. Expected behavior
Question
Context
In a Unit test, I want to send data to a FormRequest in a REST call. I am testing the behavior of the validation rules I've written in the rules method of the FormRequest.
Sources
Unit test
public function test_detach_user_job_status()
{
$response = $this->put(route('users.update', ['user' => $this->applier['id']], [
'job' => [
]
]));
$response->assertStatus(200);
}
FormRequest's rules method
public function rules()
{
return [
'name' => 'nullable|string',
'job' => 'nullable|array:id,attach_or_detach,message|required_array_keys:id,attach_or_detach',
'job.id' => 'integer|gt:0',
'job.attach_or_detach' => 'boolean',
'job.message' => 'required_if:job.attach_or_detach,true|string',
];
}
Behaviors
Actual behavior
The test succeeds.
Expected behavior
The test fails. Indeed, the array job is provided but no keys id or attach_or_detach or (eventually) message are provided, whereas the validation rules do specify: required_array_keys:id,attach_or_detach.
Also, if no job array is specified at all, then the validator must not reject the request because this array is not provided, nor its keys: it's perfectly normal since the array must be optional (it is nullable to provide this feature).
Question
Why doesn't Laravel make my test fail since my nullable (= optional) array is provided, and that its keys are required?
You didn't put the correct input. you should put the post body to put() method instead of route() method
change this:
$response = $this->put(route('users.update', ['user' => $this->applier['id']], [
'job' => [
]
]));
to:
$response = $this->put(route('users.update', ['user' => $this->applier['id']]),
[
'job' => []
]);
My form has the same input field multiple times. My form field is as follows:
<input type='text' name='items[]'>
<input type='text' name='items[]'>
<input type='text' name='items[]'>
And request contains ($request['items'):
array:1 [▼
"items" => array:3 [▼
0 => "item one"
1 => "item two"
2 => "item three"
]
]
I want atleast one of the items to be filled. My current validation in the controller is
$validator = Validator::make($request->all(),[
'items.*' => 'required|array|size:1'
]);
It does not work. I tried with combination of size, required, nullable. Nothing works.
In fact, it's enough to use:
$validator = Validator::make($request->all(),[
'items' => 'required|array'
]);
The changes made:
use items instead of items.* - you want to set rule of general items, if you use items.* it means you apply rule to each sent element of array separately
removed size:1 because it would mean you want to have exactly one element sent (and you want at least one). You don't need it at all because you have required rule. You can read documentation for required rule and you can read in there that empty array would case that required rule will fail, so this required rule for array makes that array should have at least 1 element, so you don't need min:1 or size:1 at all
You can check it like this:
$validator = Validator::make($request->all(), [
"items" => "required|array|min:1",
"items.*" => "required|string|distinct|min:1",
]);
In the example above:
"items" must be an array with at least 1 elements.
Values in the "items" array must be distinct (unique) strings, at least 1 characters long.
You can use a custom rule with a closure.
https://laravel.com/docs/5.7/validation#custom-validation-rules
To check if an array has all null values check it with array_filter which returns false if they're all null.
So something like...
$request->validate([
'items' => [
// $attribute = 'items', $value = items array, $fail = error message as string
function($attribute, $value, $fail) {
if (!array_filter($value)) {
$fail($attribute.' is empty.');
}
},
]
]);
This will set the error message: 'items is empty."
Knowing you are using the latest version of Laravel, I really suggest looking into Form Request feature. That way you can decouple validation from your controller keeping it much cleaner.
Anyways as the answer above me suggested, it should be sufficient for you to go with:
'items' => 'required|array'
Just Do it normally as you always do:
$validator = Validator::make($request->all(),[
'items' => 'required'
]);
You should try this:
$validator = $request->validate([
"items" => "required|array|min:3",
"items.*" => "required|string|distinct|min:3",
]);
I created my custom validator class that implemented ValidatorInterface. How to get element name of the fieldset or form that is validated?
I need this inside the validator class.
I am going to do some validating logic inside the class validator cause I am going to use the context array with all values and distinguish which is the current one.
Nope you can't. But you can use callable filter to re-design your value. I don't know if it's reasonable way to do it. I didn't face such a problem like this. But here's an example
$this->add([
/** other settings **/
"filters" => [
[
"name" => \Zend\Filter\Callable::class,
"options" => ["callback" => function($value){
return "fieldset-x:".$value;
}]
]
],
"validators" => [
[
"name" => \Zend\Validator\Callable::class,
"options" => ["callback" => function($value){
/** algorithm: split via ":". first element is freamwork **/
}]
]
]
])
I used callable filter and validator to do is. You may want to write your own filter/validator.
I can do something like this to validate something on the controller.
$this->validate($request,[
'myinput'=>'regex:some pattern'
]);
and the output of this would be something like this
The myinput format is invalid.
What i want was to show something of my own message
Only some pattern allowed
How do i achieve this on laravel?
There are many techniques to customize validator messages.
Validate inside the controller
It would be looked like this
$validate = Validator::make($request->all(), [
'name'=>'required|max:120',
'email'=>'required|email|unique:users,email,'.$id,
'password'=>'nullable|min:6|confirmed'
],
[
'name.required' => 'User name must not be empty!',
'name.max' => 'The maximun length of The User name must not exceed :max',
'name.regex' => 'Use name can not contain space',
'email.required' => 'Email must not be empty!',
'email.email' => 'Incorrect email address!',
'email.unique' => 'The email has already been used',
'password.min' => 'Password must contain at least 6 characters',
'password.confirmed' => 'Failed to confirm password'
]);
The first param is inputs to validate
The second array is validator rules
The last params is the customized validator messages
In which, the synctax is [input_variable_name].[validator_name] => "Customized message"
Second apprach: using InfyOm Laravel Generator
I like this approach the most. It provides useful tools for generating such as Controller, Models, Views, API etc.
And yet, create and update Request file. in which the Request file is using Illuminate\Foundation\Http\FormRequest where this class is extended from Illuminate\Http\Request.
It is mean that we can access Request in this file and perform validating for the incoming requests.
Here is the most interesting part to me.
The generated request file contains rules function, for example like this
public function rules() {
return [
'name' => 'required|unique:flights,name|max:20',
'airline_id' => 'nullable|numeric|digits_between:1,10',
];
}
This function actually returns the validator-rules and validate them against the inputs.
And you can override function messages from Illuminate\Foundation\Http\FormRequest to customize the error message as you need:
public function messages()
{
return [
'required' => "This field is required",
\\... etc
];
}
Nonetheless, you can do many nore with the generated request files, just refer to file in vendor folder vendor/laravel/framework/src/Illuminate/Foundation/Http from your project.
Here is the Infyom github link InfyOmLabs - laravel-generator
You can add custom validation messages to language files, like resources/lang/en/validation.php.
Another way to do that, from docs:
'custom' => [
'email' => [
'regex' => 'Please use your company email address to register. Webmail services are not permitted.'
],
'lawyer_legal_fields' => [
'number_of_areas' => 'You\'re not allowed to select so many practice areas'
],
],
You may customize the error messages used by the form request by overriding the messages method.
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
https://laravel.com/docs/5.3/validation#customizing-the-error-messages
In Laravel 5.1 Project
I'm getting this Ajax Response As Error
{"errors":["The Address Name field is required.","The Recipient field is required.","The Address field is required."]}
If it is not an Ajax Response in Validation we are using has method to determine which field has mistake.
As you see there exists 3 fields has errors. I'm using twitter-bootstrap and i want to show these errors like in image
How can i reach field names ? I need a has method like in normal requests.
The easiest way is to leverage the MessageBag object of the validator. It gives back the field names on the key. This can be done like this:
// Setup the validator
$rules = array('email' => 'required|email', 'password' => 'required');
$validator = Validator::make(Input::all(), $rules);
// Validate the input and return correct response
if ($validator->fails())
{
return Response::json(array(
'success' => false,
'errors' => $validator->getMessageBag()->toArray()
), 400); // 400 being the HTTP code for an invalid request.
}
return Response::json(array('success' => true), 200);
This would give you a JSON response like this:
{
"success": false,
"errors": {
"email": [
"The E-mail field is required."
],
"password": [
"The Password field is required."
]
}
}