I need to check if the key is not set in the array using Laravel validator.
That would be the complete opposite of the "required" validation rule.
Basically the array will be passed to update method if it passes the validation and I want to make sure one column will not be updated.
Is there a way to check if the value "is not present"?
Thank you
EDIT:
I'm currently using Laravel 5
EDIT:
I managed to write my own validation rule by calling Validator::extendImplicit. However I get $value as null to my validation function both when I set it to null or when I don't set it at all. Is there a way to check if the value is set?
I believe I found a solution:
$validator->extendImplicit('not_present', function($attribute, $value, $parameters)
{
return !array_key_exists($attribute, $this->data);
});
I'm not calling extendImplicit statically because the Validator class object is injected to the controller of my class.
I need to access $this->data ($this referring to the Validator object) to make sure the key doesn't exist in the array being validated.
Based on the #MaGnetas answer I came up with this 2 rules that can be applied on any model.
I'm using Laravel 5.4 so putting this lines on your AppServiceProvider.php should work.
The first approach (extendImplicit and array_key_exists)
Validator::extendImplicit('not_present', function($attribute, $value, $parameters, $validator)
{
return !array_key_exists($attribute, $validator->getData());
});
Ussing $validator->getData() we could use the Validator statically.
The second approach (extend and false)
Validator::extend('not_present', function($attribute, $value, $parameters, $validator)
{
return false;
});
You could use extend because we don't need the rule to be executed if the data has not the property (because that's exactly what we want right?)
On the docs:
By default, when an attribute being validated is not present or contains an empty value as defined by the required rule, normal validation rules, including custom extensions, are not run. more info
Important: The only difference is that using extend, empty strings will not run the validation. But if you have setting TrimStrings and ConvertEmptyStringsToNull on your middleware (which AFAIK is the default option) there will be no problem
No there is no build in validtion rule for this, but you can create your own validation rule.
The simplest way to do this:
Validator::extend('foo', function($attribute, $value, $parameters)
{
// Do some stuff
});
And check if key exists.
More information:
http://laravel.com/docs/4.2/validation#custom-validation-rules
For people looking for the not_present logic in 7.x apps (applicable for all versions), remember that you can simply use the validated data array for the same results.
$validatedKeys = $request->validate([
'sort' => 'integer',
'status' => 'in:active,inactive,archived',
]);
// Only update with keys that has been validated.
$model->update(collect($request->all())->only($validatedKeys)->all());
my model has more attributes but only these two should be updatable, therefore I too were looking for an not_present rule but ending up doing this as the results and conceptual logic is the very same. Just from another perspective.
I know this question is really old but you can also use
'email' => 'sometimes|required|not_regex:/^/i',
If the email is present in the request, the regex will match any characters in the request and if the email is an empty string but is present in request the sometimes|required will catch that.
Related
I am trying to validate a payment methods field.
Requirement is the field under validation must be of type array (Multiple values allowed) and the items should not be other than the defined option
'payment_method' => 'required|array|in:american_express,cash_on_delivery,paypal,paypal_credit_card,visa_master_card'
So the user should pass an array of values for e.g
array('american_express','paypal');
But should not pass
array('american_express', 'bank');
I am unable to find any such method in Laravel 4.1 documentation. Is there any work around for this ?
If you're using a later version of Laravel (not sure when the feature becomes available - but certainly in 5.2) you can simply do the following:
[
'payment_method' => 'array',
'payment_method.*' => 'in:american_express,cash_on_delivery,paypal,paypal_credit_card,visa_master_card'
];
You check that the payment_method itself is an array if you like, and the star wildcard allows you to match against any in the array input.
You might consider putting this into the rules() method of a request validator (that you can generate with php artisan make:request PaymentRequest as an example.
You can actually extend the Laravel validator and create your own validation rules. In your case you can very easily define your own rule called in_array like so:
Validator::extend('in_array', function($attribute, $value, $parameters)
{
return !array_diff($value, $parameters);
});
That will compute the difference between the user input array found in $value and the validator array found in $parameters. If all $value items are found in $parameters, the result would be an empty array, which negated ! will be true, meaning the validation passed. Then you can use the rule you already tried, but replace in with in_array like so:
['payment_method' => 'required|array|in_array:american_express,cash_on_delivery,paypal,paypal_credit_card,visa_master_card']
I am trying to use this validation rule in my model, but it's not working.
I mean it always remains safe even if select other option.
[['dhanwantri_bill_number'], 'safe',
'when' => function($model) {
return $model->bill_type =='d';
},
'whenClient' => "function (attribute, value) {
return $('#opdtestbill-bill_type').val() == 'd';
}"
],
Am I doing anything wrong?
is there any alternative solution to achieve the same.
Thanks.
Rule for bill_type is like
[['bill_type'], 'string', 'max' => 20],
[['bill_type','test_name','date'], 'required'],
Edit
safe attribute public properties as per doc
$when - callable - A PHP callable whose return value determines
whether this validator should be applied. yii\validators\Validator
$whenClient - string - A JavaScript function name whose return value
determines whether this validator should be applied on the client
side. yii\validators\Validator
As the 'safe' validator just tells that an attribute may be set by massive assignment, the approach is not appropiate. It just says that when you use the load() method the attribute can get a value. And if not marked as 'safe' it doesn't prevent setting a value with e.g. $model->dhanwantri_bill_number = 'asdf'. So it is not a proper solution.
More precisely: the 'safe' attribute does not have an effect when $model->validate() (which is usually called with $model->save()) gets called. It is only used when $model->load() is called. If you look into the source code of the SafeValidatior class you see that nothing happens with this validator. The validator doesn't do anything. It is just a marker (you may want to compare it to e.g. RequiredValidator). And with load() the 'when' expression is not used. So you can say 'safe' doesn't work with 'when'. The safe validator may get used when the rule gets evaluated but its validateAttribute() is empty so nothing happens in that point in time.
Besides the whenClient in your code doesn't make sense. What should happen here?
I guess there are several ways of realizing that. One idea would be to let the controller set the attributes not by load(), rather set them explicitely and check there if $model->dhanwantri_bill_number should be set or not. Or you could use load() and then revert the attribute after loading according to what $model->bill_type is set.
Or you could implement a setter method for dhanwantri_bill_number in your model and choose there if the attribute gets set or not. Maybe scenario dependent.
From Yii2 doc:
By default, an active attribute is considered safe and can be massively assigned. If an attribute should NOT be massively assigned (thus considered unsafe), please prefix the attribute with an exclamation character (e.g. '!rank').
Consider to use scenarios to handle your problem.
http://www.yiiframework.com/doc-2.0/guide-structure-models.html#scenarios
I have an input field which needs to be empty, otherwise I want the validation to fail. This is an attempt at stopping spam through a contact form.
I've looked at the documentation for the validation but there's nothing to do this, other than the "max" rule, but this doesn't work.
Any other options?
Here's a clean and (probably) bullet-proof solution:
'mustBeEmpty' => 'present|max:0',
In the method where you are validation, extend/add custom rule:
Validator::extend('mustBeEmpty', function($attr, $value, $params){
if(!empty($attr)) return false;
return true;
});
Then you may use this rule like:
protected $rules = array(
'emptyInputField' => 'mustBeEmpty'
);
Then everything is as usual, just use:
$v = Validator::make(Input::except('_token'), $rules);
if($v->passes()) {
// Passed, means that the emptyInputField is empty
}
There are other ways to do it without extending it like this or extending the Validator class but it's an easy Laravelish way to do it. Btw, there is a package available on Github as Honeypot spam prevention for Laravel applications, you may check that.
For Laravel 8.x and above, you may use the prohibited validation rule:
return [
'emptyInputField' => 'prohibited',
];
In laravel 5.8 you can use sometimes for conditional rules adding. 'email' => 'sometimes|email' . This rules will be applied if there is something present in input field.
You can use the empty rule. Details can be seen here: https://laravel.com/docs/5.2/validation#conditionally-adding-rules
If we create a simply route with Laravel 4 we can use where to set a regular expression for each param. passed in the URI. For example:
Route::get('users/{id}',function($id){
return $id;
})->where('id','\d+');
For every get request second param. must be digits. Problem comes when we create resources, if we use ->where() it throws an error about this is not an object.
I've tried to place where into a group, as an array as third param. in the resource but has not worked.How could we use the power of the regular expressions with the power of Laravel 4 resources?
He Joss,
I was going mad with the same question, so I did some research. All I could come to is the following conclusion: you do not need this method. In each of your controller methods you can specify your default values after each argument:
public function getPage(id = '0', name = 'John Doe'){
Next to this you can do a regular expression check, and a lot of other checks with the laravel validator like this:
//put the passed arguments in an array
$data['id'] = $id;
$data['name'] = $name;
//set your validation rules
$rules = array(
"id" => "integer"
"name" => "alpha"
);
// makes a new validator instance with the data to be checked with the given
// rules
$validator = Validator::make($data, $rules);
// use the boolean method passes() to check if the data passes the validator
if($validator->passes()){
return "stuff";
}
// set a error response that shows the user what's going on or in case of
// debugging, a response that confirms your above averages awesomeness
return "failure the give a response Sire";
}
Since most of the validation are already in the options list of laravel you might not need the regular expression check. Yet it is an option (regex:pattern).
My theory behind the none existence of the where() method in the controllers is that the method offers you the opportunity to do validation within you Route file. Since you already have this possibility in your controller there is just no need for it.
I am trying to register a custom validation rule but it does not seem to work. I need either of 2 fields to be filled in. One is a URL(link) field and other is a File input(file_upload).
Here is my custom validation:
Validator::register('file_check', function($attribute, $value, $parameters) {
if (!trim($value) == "" || array_get(Input::file($parameters[0]), 'tmp_name')) {
return true;
}
return false;
});
$messages = array(
'file_check' => 'Please upload a file or provide a link to files.',
);
$rules = array(
'link' => 'url|file_check:file_upload',
'file_upload' => 'mimes:jpg,jpeg,gif,png,psd,ai,bmp,xls,xlsx,doc,docx,zip,rar,7z,txt,pdf'
);
$validation = Validator::make(Input::all(), $rules, $messages);
if ($validation - > fails()) {
return Redirect::to('page') - > with_errors($validation - > errors) - > with_input();
}
Need help :)
EDITED
Also, I just noticed that the validation rule should accept "PSD" files but when I try to upload a PSD file it redirects with the error "Invalid file type".
I am maybe late in party but may be somebody will find it useful, in case you need to create implicit rule which will be called even if field is not present in Input (like required,required_if....) use
Validator::extendImplicit( 'validator_name', function($attribute, $value, $parameters)
{
});
Check this out
I was just struggling with this myself! It turns out that except when a few specific rules are applied to them, Laravel doesn't pass empty fields through the Validator at all. So a custom either-this-or-that rule can't work, since at least one of the two fields is likely to not be visible to it.
You can get around this by moving from the registering-a-new-rule approach to the alternate extend-the-Validator-class approach. Your new class will inherit all the methods of the standard Validator, including a method called "implicit" (you can find the original on line 215 of the standard Validator class), which specifies a whitelist of rules that Laravel should pass fields along to even if they are empty. Add your new rule to that list and you should be good to go.
Jason is right, but there is one thing that can be confusing.
Laravel's 'registering a new rule' approach uses the syntax 'Validator::extend(...'. As described elsewhere, this is convenient when you want to customize in a special situation. However, if you want to add a number of reusable rules, then you probably want to use the extend-the-Validator-class approach. In that case, IF you have a rule conditionally requires something, you need to override the existing implicitRules array with a new one adding your rule.
If the first rules you add don't conditionally require, you will think you have it nailed, then you will spend hours trying to figure out why your new 'RequireWhenBlaBla...' rule is invisible.