I use Form Request Validation in one of my Laravel projects, and want to validate country_id but only if bak_leaflet ist set to 0. In my FormRequestFile i have the following rules:
public function rules()
{
return [
...
'country_id' => 'required_if:bak_leaflet,0',
...
];
}
This works absolutely fine, but when bak_leaflet is 0, then country_id also needs to be larger than 1:
public function rules()
{
return [
...
'country_id' => 'required_if:bak_leaflet,0|min:1',
...
];
}
However, the min:1 rule gets ignored completely. How can I make sure the validation works how I need it to?
You can add a validation extender in your AppServiceProvider's boot() method, like this:
\Validator::extend('min_if', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
if (isset($data[$parameters[0]]) && $data[$parameters[0]] == $parameters[1] && (int)$value < $parameters[2]) {
return false;
}
return true;
});
Then write your validation rule like this:
'country_id' => 'required_if:bak_leaflet,0|min_if:bak_leaflet,0,1',
Additionally you will need to add
'min_if' => 'Your validation message',
into resources/lang/en/validation.php or pass to your $this->validate() as third paramater
I've used the answer of #avik-aghajanyan and added the method to my form request file as follows:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Factory as ValidationFactory;
class StoreArticle extends FormRequest
{
public function __construct(ValidationFactory $validationFactory)
{
$validationFactory->extend('min_if', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
if (isset($data[$parameters[0]]) && $data[$parameters[0]] == $parameters[1] && (int)$value < $parameters[2]) {
return false;
}
return true;
});
}
....
Related
I have an issue validating the request parameters to filter the records recieved in the query string
$validator = Validator::make($request->request->all(), [
'filter' =>
[
'array',
Rule::in(implode(',',$columns))
],
'page' =>'integer'
]);
Where the coulmns include id, name, size etc. and the API request has the following format
./findAll?filter[id]=1&filter[name]=test
I want to return a 400 response when any filter is passed which does not exist as a column.
You can use Validator extension to make your own validator:
In AppServiceProvider's put this code: (or in any provider)
public function boot(){
Validator::extend('keys_in', function ($attribute, $value, $arr, $validator) {
if (!is_array($value)) return false;
foreach (array_keys($value) as $key) {
if (!in_array($key, $arr)) return false;
}
return true;
});
Validator::extend('keys_in_columns', function ($attribute, $value, $table, $validator) {
if (!is_array($value)) return false;
$columns = Schema::getColumnListing($table);
foreach (array_keys($value) as $key) {
if (!in_array($key, $columns)) return false;
}
return true;
});
}
The custom validator Closure receives four arguments: the name of the $attribute being validated, the $value of the attribute, an array of $parameters passed to the rule, and the Validator instance.
Then in any controller you can use this two rules:
$validator = Validator::make($request->request->all(), [
'filter' =>['array','keys_in:' . implode(',',$columns)],
'page' =>'integer'
]);
Or use keys_in_columns shortcut which I defined above:
$validator = Validator::make($request->request->all(), [
'filter' =>['array','keys_in_columns:users'],
'page' =>'integer'
]);
don't forget to use use Illuminate\Support\Facades\Schema; and use Illuminate\Support\Facades\Validator; in Service Provider
Hope this helps you
I have a form in route('users.create').
I send form data to this function in its contoller:
public function store(UserRequest $request)
{
return redirect(route('users.create'));
}
for validation I create a class in
App\Http\Requests\Panel\Users\UserRequest;
class UserRequest extends FormRequest
{
public function rules()
{
if($this->method() == 'POST') {
return [
'first_name' => 'required|max:250',
It works.
But How can I change first_name value before validation (and before save in DB)?
(Also with failed validation, I want to see new data in old('first_name')
Update
I try this:
public function rules()
{
$input = $this->all();
$input['first_name'] = 'Mr '.$request->first_name;
$this->replace($input);
if($this->method() == 'POST') {
It works before if($this->method() == 'POST') { But It has not effect for validation or for old() function
Override the prepareForValidation() method of the FormRequest.
So in App\Http\Requests\Panel\Users\UserRequest:
protected function prepareForValidation()
{
if ($this->has('first_name'))
$this->merge(['first_name'=>'Mr '.$this->first_name]);
}
Why not doing the validation in the controller? Than you can change things before you validate it and doing your db stuff afterward.
public function store(Request $request)
{
$request->first_name = 'Mr '.$request->first_name;
Validator::make($request->all(), [
'first_name' => 'required|max:250',
])->validate();
// ToDo save to DB
return redirect(route('users.create'));
}
See also https://laravel.com/docs/5.5/validation
Simply use
$request->merge(['New Key' => 'New Value']);
In your case it can be as follows for saving
$this->merge(['first_name'=>'Mr '.$this->first_name]);
I've a custom validator, see below (simplified)
Form Request
public function rules()
{
return [
'amount' => 'required|numeric|max_invest:10000'
];
}
public function messages()
{
return [
'max_invest' => 'You can invest max :mi' // I want to set :mi on the fly
];
}
Validator
public function validateMaxInvestment($attribute, $value, $parameters, $validator)
{
$this->setAttributeNames(['mi' => intval($parameters[0] - $value)]); // Try to set the attribute mi on the fly
return $value < $parameters[0];
}
I did register the validator in the boot method of my service provider, like so:
$this->app['validator']->extend('maxInvestment',
'MaxInvestmentValidator#validateMaxInvestment');
The problem
The validator works fine, but the message I get stays:
You can invest max :mi
Calling the method setAttributeNames doesn't take effect.
You need to use a replacer for that purpose which you may miss as it is at the bottom of the documentation.
When creating a custom validation rule, you may sometimes need to
define custom place-holder replacements for error messages. You may do
so by creating a custom Validator as described above then making a
call to the replacer method on the Validator facade. You may do this
within the boot method of a service provider:
public function boot() {
Validator::extend(...);
Validator::replacer('foo', function($message, $attribute, $rule, $parameters) {
return str_replace(...);
});
}
So for your case, something like below should work.
protected function validateMaxInvestment($attribute, $value, $parameters, $validator)
{
$replace = intval($parameters[0] - $value);
$validator->addReplacer('max_invest', function ($message) use ($replace) {
return str_replace(':mi', $replace, $message);
});
return $value < $parameters[0];
}
Also, not sure but I guess you can also do something like below.
protected function validateMaxInvestment($attribute, $value, $parameters, $validator)
{
return $value < $parameters[0];
}
protected function replaceMaxInvestment($message, $attribute, $rule, $parameters)
{
$replace = intval($parameters[0] - \Input::get($attribute));
return str_replace(':mi', $replace, $message);
}
Hence, probably you will need to register it again.
$this->app['validator']->replacer('maxInvestment', 'MaxInvestmentValidator#replaceMaxInvestment');
I have code in Request class:
public function rules()
{
return [
'id' => 'required|check_xxx',
];
}
public function attributes()
{
return [
'id' => 'AAA',
];
}
As you can see. I have cusom validation method name check_xxx. This method in inside class CustomValidator.
So, I have code:
class ValidationServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->validator->resolver(function ($translator, $data, $rules, $messages) {
return new CustomValidator($translator, $data, $rules, $messages);
});
}
}
And error message for required is: Please input :attribute
But I got the message: Please input id, (TRUE is: Please input AAA)
I discovered that $this->app->validator->resolver make attributes() method in Request is useless.
How can I fix that? Thank you.
I had this issue in Laravel 5.2 but found a QUICK solution as following. In example following you will add rule directly inside the APP Provider.
File to add rule: app/Providers/AppServiceProvider.php
public function boot()
{
// ....
#/
#/ Adding rule "even_number" to check even numbers.
#/
\Validator::extend('even_number', function($attribute, $value, $parameters, $validator) {
$value = intval($value);
return ($value % 2) == 0);
// ...
}
Is it possible to do something similar to the following in Laravel:
public function rules()
{
return [
'sid' => function ($input) {
// some custom validation logic.
}
];
}
public function messages()
{
return [
'sid' => "Invalid SID!",
];
}
I want to do some simple single-use validation. Creating a custom validation is an overkill.
If you are using Laravel 5.6 or later, you may use closures.
To have $input available in the scope of the closure, you may use use keyword.
'sid' => [ function($attribute, $value, $fail) use $input {
// your logic here
//if that fails, so
return $fail($attribute.' is invalid.');
}
]
There are two options here, at least.
Create a custom rule via AppServiceProvider at boot() method:
Validator::extend('my_rule', function($attribute, $value, $parameters) {
// some custom validation logic in order to return true or false
return $value == 'my-valid-value';
});
then, you apply the rule like:
return [
'sid' => ['my_rule'],
];
Or extending ValidatorServiceProvider class. Use this thread explained step by step: Custom validator in Laravel 5