Conditional form validation in CakePHP 3 - php

I want to validate some fields from validationDefault() function not all because of conditions but did not find any solution.
Example:
public function validationDefault(Validator $validator) {
$validator
->requirePresence('title', 'create')
->notEmpty('title');
$validator
->requirePresence('inquiry')
->allowEmpty('inquiry');
$validator
->requirePresence('dosage')
->allowEmpty('dosage');
$validator
->requirePresence('dosage_occurance')
->integer('dosage_occurance')
->allowEmpty('dosage_occurance');
return $validator;
}
Note: Response coming from two diffrent form first contains(title and inquiry) other contains(title, dosage and dosage_occurance).
I want to validate it from validationDefault() but it give me error
"dosage_occurance": {
"_required": "This field is required"
}
when I am not sending dosage_occurance which is correct but according to condition it is wrong.
using fieldList while creating new entity but it is not working.
Thanks

You want conditional validation.
Taken from the documentation:
When defining validation rules, you can use the on key to define when a validation rule should be applied. If left undefined, the rule will always be applied. Other valid values are create and update. Using one of these values will make the rule apply to only create or update operations.
Read the whole documentation page.
Example taken from there, pay attention to the on part.
$validator->add('picture', 'file', [
'rule' => ['mimeType', ['image/jpeg', 'image/png']],
'on' => function ($context) {
return !empty($context['data']['show_profile_picture']);
}
]);

Related

Laravel Validation: Second rule does not run

I have this validation in my controller:
$rules = [
'participants' => 'required|atleast_one'
];
Validator::extendImplicit('atleast_one', function ($attribute, $value, $parameters, $validator) {
// Long conditions.
// Returns true or false
});
$error = Validator::make($request->all(), $rules);
The second rule atleast_one is a custom rule using the extend method.
I tested this rule alone and it works. But why is it when I put the two rules together ('participants' => 'required|atleast_one'), the second one doesn't work? I tried rearranging it and still the same, the second rule doesn't work. Did I miss something on the Laravel documentation?

Laravel 5.2 - validation - One of the fields is required

Take a scenario,
There are 2 fields available in the form.
1) input type file for manual upload.
2) input type = text to enter youtube video url.
is it possible using laravel built-in validations so that validation will be fired if user has left both fields empty!
I have gone through https://laravel.com/docs/5.3/validation but could not find what I wanted.
In your controller, you could do something like this:
$validator = Validator::make($request->all(), [
'link_upload' => 'required|etc|...',
]);
$validator2 = Validator::make($request->all(), [
'file_upload' => 'required|etc|...',
]);
if ($validator->fails() && $validator2->fails()) {
// return with errors
}
Try required-without-all validation rule. As given in documentation:
The field under validation must be present only when the all of the other specified fields are not present.
Assuming your fields name are url and file, your rule would be like below:
$rules = [
'url' => 'required_without_all:file',
'file' => 'required_without_all:url'
];
required_without:foo,bar,...
The field under validation must be present and not empty only when any of the other specified fields are not present.
Try this,
In youre update method add this
$this->validate($request, [
'fileName'=>'required',
'urlName'=>'required'
]);
dont forget to set the fillable in your model
protected $fillable = ['fileName','urlName'];
Hope this helps

CakePHP 3 - Cake trying to validate notEmpty for some reason

My table is throwing a default "notEmpty" validation error, even though I have not written any validation of the sort.
Basic validation in my Table class:
public function validationDefault(Validator $validator)
{
return $validator->requirePresence('my_field', 'create', 'Custom error message');
}
Data being set:
['my_field' => null]
As far as I can tell from the docs, this should not fail validation.
Key presence is checked by using array_key_exists() so that null values will count as present.
However, what is actually happening is that validation is failing with a message:
'my_field' => 'This field cannot be left empty'
This is Cake's default message for the notEmpty() validation function, so where is it coming from? I want it to allow the null value. My database field also allows NULL.
Edit
I have managed to solve the issue by adding allowEmpty() to the validation for that field. This would, therefore, seem to show that Cake assumes that if your field is required you also want it validate notEmpty() by default, even if you didn't tell it so.
This directly contradicts the documentation line I showed above:
Key presence is checked by using array_key_exists() so that null values will count as present.
So does the documentation need to be updated, or is it a bug?
Although it is not mentioned in the Cake 3 documentation, required fields are not allowed to be empty by default, so you have to explicitly state that the field is required and allowed to be empty.
public function validationDefault(Validator $validator)
{
return $validator
->requirePresence('my_field', 'create', 'Custom error message')
->allowEmpty('my_field', 'create');
}
This had me stumped for a while. The default behaviour is not at all intuitive. Here's some code that applies conditional validation on an array of scenarios coded as [ targetField, whenConditionalField, isConditionalValue ]
public function validationRegister()
{
$validator = new Validator();
$conditionals = [ ['shipAddress1','shipEqualsBill','N'], ['shipTown','shipEqualsBill','N'], ['shipPostcode','shipEqualsBill','N'] ];
foreach($conditionals as $c) {
if (!is_array($c[2])) $c[2] = [$c[2]];
// As #BadHorsie says, this is the crucial line
$validator->allowEmpty($c[0]);
$validator->add($c[0], 'notEmpty', [
'rule' => 'notEmpty',
'on' => function ($context) use ($c) {
return (!empty($context['data'][$c[1]]) && in_array($context['data'][$c[1]], $c[2]));
}
]);
}
return $validator;
}
So, in this case, if the user selects that the Shipping Address is not the same as the Billing Address, various shipping fields must then be notEmpty.

cakephp3 custom validation

I have a duration field that sometimes can be empty and sometimes can't, depending on the other data sent by the form. So I'm trying to do custom validation in CakePHP3.
In my table I did
public function validationDefault(Validator $validator)
{
$validator
->add('duration', 'durationOk', [
'rule' => 'isDurationOk',
'message' => 'duration is not OK',
'provider' => 'table'
]);
return $validator;
}
public function isDurationOk($value, $context)
{
// do some logic
return false; // Always return false, just for test
}
Now when I set the value for duration field I get an 'duration is not OK' error (as expected). But when I let the value empty I get a 'This field cannot be left empty' error.
So I added:
->allowEmpty('duration');
But in this case when duration is empty I don't get an error at all.
Am I doing something wrong or it's just me don't understanding how validation works?
Let me read the book for you:
Conditional Validation
When defining validation rules, you can use the on key to define when
a validation rule should be applied. If left undefined, the rule will
always be applied. Other valid values are create and update. Using one
of these values will make the rule apply to only create or update
operations.
Additionally, you can provide a callable function that will determine
whether or not a particular rule should be applied:
'on' => function ($context) {
// Do your "other data" checks here
return !empty($context['data']['other_data']);
}
So just define the conditions depending on your "other data" in the callback to apply the rule only when the conditons are true.
Alternatively you can manipulate the plain form data even before it gets validated in the beforeMarshal() callback of the table and change the form data as needed or load another validator or modify the validator.

Validator - return all error messages

Currently the Validator in Laravel only appears to return one error message per field, despite the field potentially having multiple rules and messages. (Note: I'm currently passing an empty array as $data to Validator::make)
What I'm trying to do is build an array of each field's rules and messages that could potentially be re-used for front end validation. Something like this:
{
"name": {
"required": [
"The name field is required."
],
"max:255": [
"The name field may not be greater than 255."
]
},
"email": {
"required": [
"The email field is required."
],
"email": [
"The email field must be a valid email address."
],
"max:255": [
"The email field may not be greater than 255."
]
}
}
The getMessage method in Illuminate\Validation\Validator looks like it would get me close to being able to construct something myself, however it is a protected method.
Does anyone know of a way to get a Validator instance to output all rules and messages?
Currently the Validator in Laravel only appears to return one error message per field, despite the field potentially having multiple rules and messages.
Validation of given field stops as soon as a single validation rule fails. That's the reason you're getting only single error message per field.
As of fetching the validation messages like in the example you provided, Laravel's validator does not provide such option, but you could easily achieve that by extending the Validator class.
First, create your new class:
<?php namespace Your\Namespace;
use Illuminate\Validation\Validator as BaseValidator;
class Validator extends BaseValidator {
public function getValidationMessages() {
$messages = [];
foreach ($this->rules as $attribute => $rules) {
foreach ($rules as $rule) {
$messages[$attribute][$rule] = $this->getMessage($attribute, $rule);
}
}
return $messages;
}
}
As you can see the output is a bit different than your example. There is no need to return an array of messages for given attribute and rule, as there will be always only one message in the array, so I'm just storing a string there.
Second, you need to make sure that your validator class is used. In order to achieve that, you'll need to register your own validator resolver with Validator facade:
Validator::resolver(function($translator, array $data, array $rules, array $messages, array $customAttributes) {
return new \Your\Namespace\Validator($translator, $data, $rules, $messages, $customAttributes);
});
You can do this in your AppServiceProvider::boot() method.
Now, in order to get validation messages for given validator, you just need to call:
Validator::make($data, $rules)->getValidationMessages();
Keep in mind this code hasn't been tested. Let me know if you see any issues or typos with the code and I'll be more than happy to get that working for you.

Categories