How to bypass muliple validation attribute values inside validation messages in Laravel? - php

I've made a custom validator, that compares two dates, and I want to show a message to the user which says the one date (the invoicedate in my example) must be earlier than the other one (the deadline in my example).
Inside my custom validator I write:
public static validateInfo(Request $request)
{
$validator = Validator::make($request->all(), [
'referencenumber' => 'required|min:2|max:64',
'invoicedate' => 'required|date',
'deadline' => 'null|date'
]);
$validator->after(function ($validator) use ($request) { // custom static function where I compare two dates using strtotime(), if invoicedate and deadline are still valid, and return false or true
if (InvoiceValidator::invalidDeadline($validator, $request)) {
$validator->errors()->add('deadline', __('validation.negative_date_difference', [
'attribute1' => 'deadline',
'attribute2' => 'invoicedate'
]));
}
});
return $validator;
}
And inside resources\lang\en\validation.php I write:
<?php
return [
// ...
'negative_date_difference' => 'The :attribute1 may not be earlier than the :attribute2.',
// ...
'attributes' => [
'referencenumber' => 'Reference Number', // This works. It's fine
'invoicedate' => 'Invoice Date' // But this does not work, of course, because I wrote $validator->errors()->add('deadline'...); so the deadline is the only targetted attribute name here
],
]
Current output is:
The Deadline may not be earlier than the invoicedate.
My question: how to bypass invoicedate, when this is the message I want to see?
The Deadline may not be earlier than the Invoice Date.

Inside resources\lang\en\messages.php I've added a new message:
<?php
return [
'invoice_date' => 'Invoice Date'
]
Then edited my custom validation function, as follows:
if (InvoiceValidator::invalidDeadline($validator, $request)) {
$validator->errors()->add('deadline', __('validation.negative_date_difference', [
'attribute1' => 'deadline',
'attribute2' => __('messages.invoice_date') // This works
]));
}

Related

How can I conditionally validate a custom rule in Laravel?

In my controller I have a store method that is validating the request data:
$request->validate([
'title' => 'required',
'description' => 'required',
'date' => [
'required',
new DateFormatRule
],
'closed' => 'nullable',
'time_start' => 'required_if:closed,0',
'time_end' => [
'required_if:closed,0',
new TimeDurationRule($request->time_start)
],
]);
closed is a boolean. If closed is false, the time_start and time_end fields are required. This seems to be working as expected.
However, if I submit a request with closed as true, I am getting caught in my custom TimeDurationRule:
'time_end' => [
'required_if:closed,0',
new TimeDurationRule($request->time_start)
],
How can I make new TimeDurationRule($request->time_start) conditional? For example, if closed is true, I am manually setting time_end to null so time_start/time_end do not need a value (not required).
If I comment my custom rule out, everything works as expected.
Thank you for any suggestions!
You can pass $request->closed to your TimeDurationRule and then in the passes method of the rule, you can do something like this:
class TimeDurationRule implements Rule
{
public $closed;
public function __construct(/*all needed parameters*/, $closed)
{
$this->closed = $closed;
}
public function passes($attribute, $value)
{
if(!$closed){
return true
}
// the rest of validation logic
}
}
And then
new TimeDurationRule(/*all needed parameters*/, $request->closed)
You can read more about it here as well: https://laracasts.com/discuss/channels/laravel/create-custom-validation-rule-with-additional-parameters-implement-in-request
Hope it helps!

How do I get ONLY the validated data from a laravel FormRequest?

Lets say I have the following Custom Request:
class PlanRequest extends FormRequest
{
// ...
public function rules()
{
return
[
'name' => 'required|string|min:3|max:191',
'monthly_fee' => 'required|numeric|min:0',
'transaction_fee' => 'required|numeric|min:0',
'processing_fee' => 'required|numeric|min:0|max:100',
'annual_fee' => 'required|numeric|min:0',
'setup_fee' => 'required|numeric|min:0',
'organization_id' => 'exists:organizations,id',
];
}
}
When I access it from the controller, if I do $request->all(), it gives me ALL the data, including extra garbage data that isn't meant to be passed.
public function store(PlanRequest $request)
{
dd($request->all());
// This returns
[
'name' => 'value',
'monthly_fee' => '1.23',
'transaction_fee' => '1.23',
'processing_fee' => '1.23',
'annual_fee' => '1.23',
'setup_fee' => '1.23',
'organization_id' => null,
'foo' => 'bar', // This is not supposed to show up
];
}
How do I get ONLY the validated data without manually doing $request->only('name','monthly_fee', etc...)?
$request->validated() will return only the validated data.
Example:
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
$validatedData = $request->validated();
}
Alternate Solution:
$request->validate([rules...]) returns the only validated data if the validation passes.
Example:
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
}
OK... After I spent the time to type this question out, I figured I'd check the laravel "API" documentation: https://laravel.com/api/5.5/Illuminate/Foundation/Http/FormRequest.html
Looks like I can use $request->validated(). Wish they would say this in the Validation documentation. It makes my controller actions look pretty slick:
public function store(PlanRequest $request)
{
return response()->json(['plan' => Plan::create($request->validated())]);
}
This may be an old thread and some people might have used the Validator class instead of using the validator() helper function for request.
To those who fell under the latter category, you can use the validated() function to retrieve the array of validated values from request.
$validator = Validator::make($req->all(), [
// VALIDATION RULES
], [
// VALIDATION MESSAGE
]);
dd($validator->validated());
This returns an array of all the values that passed the validation.
This only starts appearing in the docs since Laravel 5.6 but it might work up to Laravel 5.2

How to validate array in Laravel?

I try to validate array POST in Laravel:
$validator = Validator::make($request->all(), [
"name.*" => 'required|distinct|min:3',
"amount.*" => 'required|integer|min:1',
"description.*" => "required|string"
]);
I send empty POST and get this if ($validator->fails()) {} as False. It means that validation is true, but it is not.
How to validate array in Laravel? When I submit a form with input name="name[]"
Asterisk symbol (*) is used to check values in the array, not the array itself.
$validator = Validator::make($request->all(), [
"names" => "required|array|min:3",
"names.*" => "required|string|distinct|min:3",
]);
In the example above:
"names" must be an array with at least 3 elements,
values in the "names" array must be distinct (unique) strings, at least 3 characters long.
EDIT: Since Laravel 5.5 you can call validate() method directly on Request object like so:
$data = $request->validate([
"name" => "required|array|min:3",
"name.*" => "required|string|distinct|min:3",
]);
I have this array as my request data from a HTML+Vue.js data grid/table:
[0] => Array
(
[item_id] => 1
[item_no] => 3123
[size] => 3e
)
[1] => Array
(
[item_id] => 2
[item_no] => 7688
[size] => 5b
)
And use this to validate which works properly:
$this->validate($request, [
'*.item_id' => 'required|integer',
'*.item_no' => 'required|integer',
'*.size' => 'required|max:191',
]);
The recommended way to write validation and authorization logic is to put that logic in separate request classes. This way your controller code will remain clean.
You can create a request class by executing php artisan make:request SomeRequest.
In each request class's rules() method define your validation rules:
//SomeRequest.php
public function rules()
{
return [
"name" => [
'required',
'array', // input must be an array
'min:3' // there must be three members in the array
],
"name.*" => [
'required',
'string', // input must be of type string
'distinct', // members of the array must be unique
'min:3' // each string must have min 3 chars
]
];
}
In your controller write your route function like this:
// SomeController.php
public function store(SomeRequest $request)
{
// Request is already validated before reaching this point.
// Your controller logic goes here.
}
public function update(SomeRequest $request)
{
// It isn't uncommon for the same validation to be required
// in multiple places in the same controller. A request class
// can be beneficial in this way.
}
Each request class comes with pre- and post-validation hooks/methods which can be customized based on business logic and special cases in order to modify the normal behavior of request class.
You may create parent request classes for similar types of requests (e.g. web and api) requests and then encapsulate some common request logic in these parent classes.
Little bit more complex data, mix of #Laran's and #Nisal Gunawardana's answers
[
{
"foodItemsList":[
{
"id":7,
"price":240,
"quantity":1
},
{
"id":8,
"quantity":1
}],
"price":340,
"customer_id":1
},
{
"foodItemsList":[
{
"id":7,
"quantity":1
},
{
"id":8,
"quantity":1
}],
"customer_id":2
}
]
The validation rule will be
return [
'*.customer_id' => 'required|numeric|exists:customers,id',
'*.foodItemsList.*.id' => 'required|exists:food_items,id',
'*.foodItemsList.*.quantity' => 'required|numeric',
];
You have to loop over the input array and add rules for each input as described here: Loop Over Rules
Here is a some code for ya:
$input = Request::all();
$rules = [];
foreach($input['name'] as $key => $val)
{
$rules['name.'.$key] = 'required|distinct|min:3';
}
$rules['amount'] = 'required|integer|min:1';
$rules['description'] = 'required|string';
$validator = Validator::make($input, $rules);
//Now check validation:
if ($validator->fails())
{
/* do something */
}
The below code working for me on array coming from ajax call .
$form = $request->input('form');
$rules = array(
'facebook_account' => 'url',
'youtube_account' => 'url',
'twitter_account' => 'url',
'instagram_account' => 'url',
'snapchat_account' => 'url',
'website' => 'url',
);
$validation = Validator::make($form, $rules);
if ($validation->fails()) {
return Response::make(['error' => $validation->errors()], 400);
}
In my Case it works fine
$validator = Validator::make($request->all(), [
"names" => "required|array|min:3",
"*.names"=> "required|string|distinct|min:3",
]);

Laravel 5.2 validation: date_format:Y.m.d not working

I try to validate a POST request.
The format is: d.m.Y (12.1.2017)
My rule is required|date_format:d.m.Y for this field.
I get this error message:
InvalidArgumentException in Carbon.php line 425:
Unexpected data found.
Unexpected data found.
Data missing
If I change the . to - or even / it is working -> POST data changed before to match the rule.
I need the German format for this.
edit:
My validation rules:
public function rules()
{
return [
'title' => 'required|max:255',
'expiration_date' => 'required|date_format:d.m.Y',
//'description' => 'required',
'provision_agent' => 'required|integer|between:0,100',
'discount_consumer' => 'required|integer|between:0,100',
'quota' => 'required|integer',
];
}
Wrap your Format should work i just tried with 5.2 it's working fine.
public function rules()
{
return [
'title' => 'required|max:255',
'expiration_date' => 'required|date_format:"d.m.Y"',
//'description' => 'required',
'provision_agent' => 'required|integer|between:0,100',
'discount_consumer' => 'required|integer|between:0,100',
'quota' => 'required|integer',
];
}
But the error what you added in question InvalidArgumentException in Carbon.php line 425: it seems something else my guess you are using expiration_date some where in controller or model like this with Carbon
echo Carbon::createFromFormat('Y-m-d', '12.1.2017');
You should try something like this
echo Carbon::parse('12.1.2017')->format('Y-m-d')
Wrap your format into quotes:
'date_format:"d.m.Y"'
Try like this,
public function rules()
{
return [
'title' => 'required|max:255',
'expiration_date' => 'date_format:"d.m.Y"|required', // I have changed order of validation
//'description' => 'required',
'provision_agent' => 'required|integer|between:0,100',
'discount_consumer' => 'required|integer|between:0,100',
'quota' => 'required|integer',
];
}
Hope this will solve your problem.
If you don't succeed solving the issue otherwise, you can still use a custom validation rule:
Validator::extend('date_dmY', function ($attribute, $value) {
$format = 'd.m.Y';
$date = DateTime::createFromFormat($format, $value);
return $date && $date->format($format) === $value;
}, 'optional error message');
The extra check $date->format($format) === $value is to avoid erroneously accepting out-of-range dates, e.g. "32.01.2017". See this comment on php.net.
Once the custom validation rule has been defined, you can use it like so:
public function rules() {
return [
'expiration_date' => 'required|date_dmY',
];
}

Laravel custom validation rule

How can i make a custom validation rule to an input which value must be an integer and starting with 120?
I already read about making custom messages but didnt understand about rules.
I want to use a regex to validate the data. ^120\d{11}$ here is my regex.
I'm new in Laravel that's why cant now imagine how to do that.
A custom validation to use it in $this->validate($request, []);
Now i'm validating data like so:
$this->validate($request, [
'user_id' => 'integer|required',
'buy_date' => 'date',
'guarantee' => 'required|unique:client_devices|number',
'sn_imei' => 'required|unique:client_devices',
'type_id' => 'integer|required',
'brand_id' => 'integer|required',
'model' => 'required'
]);
The input that i want to add custom validation is guarantee
The quickest neatest way is an inline validator in your controller action:
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'number' => [
'regex' => '/^120\d{11}$/'
],
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
return view('welcome');
}
Where number is the name of the field being submitted in the request.
If you have a lot of validation to do, you might want to consider using a Form Request instead, as a way of consolidating a lot of validation logic.
You can create custom validations in your controller as:
$name = Input::get('field-name')
$infoValidation = Validator::make(
array( // Input array
'name' => $name,
),
array( // rules array
'name' => array("regex:/^120\d{11}$"),
),
array( // Custom messages array
'name.regex' => 'Your message here',
)
); // End of validation
$error = array();
if ($infoValidation->fails())
{
$errors = $infoValidation->errors()->toArray();
if(count($errors) > 0)
{
if(isset($errors['name'])){
$response['errCode'] = 1;
$response['errMsg'] = $errors['name'][0];
}
}
return response()->json(['errMsg'=>$response['errMsg'],'errCode'=>$response['errCode']]);
}
Hope this helps.
Since Laravel 5.5, you can make the validation directly on the request object.
public function store(Request $request)
{
$request->validate([
'guarantee' => 'regex:/^120\d{11}$/'
]);
}

Categories