Differences between sometimes and nullable in Laravel validation - php

Let's assume I can do validation in two ways
'active' => {
'sometimes',
}
and
'active' => {
'nullable',
}
What's the difference? When the one will pass and the other won't?
And the same question about this:
'user_id' => {
'sometimes|exists:user,id',
}
and
'user_id' => {
'nullable|exists:user,id',
}
I've read multiple posts on a subject, including the documentation and I still don't get it. Does sometimes or nullable make even sense when using with no other rules (like in my first example)?

Nullable:
Laravel converts empty value to null using middleware ConvertEmptyStringsToNull. Because of this, you will often need to mark your "optional" request fields as nullable if you do not want the validator to consider null values as invalid.
Sometimes :
If you want to validate the field only if the field is present in request. This is useful when we manipulate the DOM using javascript or jQuery.
Read More

Related

Form request validation in Laravel: required depending on the method (POST, PUT or DELETE)

I am using form requests in Laravel for validation. I have noticed a pattern that emerges all the time and I couldn't find a solution for it on SE (or at least googling it didn't help me).
Let's say we are creating an API and we are using Laravel's apiResource to create the usual CRUD methods: store, update and delete
Obviously, when we are storing a new record, the field id is not required, but the rest of the fields might be required (and in most cases are). But when we are updating a record, we face the opposite situation. id is required while other fields are no longer required.
Is it possible to handle this situation with one form request in Laravel? Can we use Laravel's required_if in an intelligent way to avoid code duplication?
Edit: it doesn't have to be necessarily a Laravel solution. A solution that uses PHP would be fine too (as long as it is clean and follows SOLID principles).
I faced this problem lots of times and I understand your frustration...
From my point of view and professional experience, the best solution was all the time to have specific FormRequests for each case:
One for store with its own rules
Other for update with similar rules but not same as store
And last one for delete (for sure way less rules than the others and no duplication)
I know you said "no code duplication", but as it is right now, that is not possible (but you should not have code duplication as I stated before).
You said "as long as it is clean and follows SOLID principles", remember SOLID, S = Single Responsability, so if you want to solve this issue with a single FormRequest you are already breaking S. I cannot image a FormRequest with 10 or 15 inputs and those depends on if it is store, update, or delete. That is going to not be clean and for sure will not follow SOLID principles.
What about checking the method and then returning a set of rules based on that method? For instance, I have an InvoiceFormRequest with the following rules. So I'm able to use one form request for two different methods.
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
if ($this->isMethod('post')) {
return [
'template' => 'required',
'due_by_date' => 'required',
'description' => 'required',
'charge_items' => 'required',
];
}
if ($this->isMethod('put')) {
return [
'due_by_date' => 'required',
'description' => 'required',
'charge_items' => 'required',
];
}
}
Here are two possible solutions that I came up with
Use the controller method for returning the proper validation rules:
public function rules()
{
$method = $this->route()->getActionMethod();
switch($method){
case 'store':
return [
\\ validation rules
]
...
}
}
Use $this->getMethod() instead of $this->route()->getActionMethod() and validate by HTTP methods instead.
You could also store your validation rules in an array and manipulate it to reduce code duplication.
This resolves the issue of code duplication to a good extent, I think.

required_if validation in Laravel

I am trying to add a rule to validate a field. The 'snippet' field needs to be required only if the body field contains HTML. I have the following in my controller store method, but I can't quite figure out how the required_if would work in conjunction with a regex for checking if the field contains HTML:
$newsitem->update(request()->validate([
'snippet' => 'nullable|max:255|not_regex:/[<>]/',
'body' => 'required',
]));
From the Laravel docs, it looks like the: 'required_if:anotherfield,value' validation rule returns a boolean based on a value, but I need to return a boolean based on a regex check of the body field.
I know I could check if the body is equal to one:
'snippet' => 'required_if:body,==,1|nullable|max:255|not_regex:/[<>]/'
...but I need something that checks if the body contains < or >.
(I could add a hidden field in my form submission which would get a value set if the body contained html using javascript, but I wanted to be able to handle this with backend validation.)
Do I need to use a custom validation rule, or can this be handled with the default Laravel validation rules alone?
I have seen in the Laravel docs that you can use the: Rule::requiredIf method to build more complex conditions. Is this something I can use alongside a contains_hmtl function?
'snippet' => Rule::requiredIf($request->snippet()->contains_html),
I really feel like I am missing something here, so any pointers would be much appreciated.
Try the following regex with RequiredIf:
[
...,
'snippet' => ['nullable', 'max:255', new RequiredIf(function () {
return preg_match('/<[^<]+>/m', request()->input('body')) !== 0;
})],
...,
]
RequiredIf rule accepts a closure which should return a boolean value.
Rule::requiredIf(function () use ($request) {
//Perform the check on $request->snippet to determine whether it is a valid HTML here
//Return true if it is valid HTML else return false
}),

Laravel nullable validation rule not working

I recently upgraded to laravel 5.4 (from 5.2) to make use of the nullable validation rule.
I have a field act_post_code which can be either an integer OR null. So I provided the following rule in my Request class.
'act_post_code' => 'integer|nullable'
In Postman using form-data, I provide a key = act_post_code with its value = null.
The response I get is the following:
{
"act_post_code": [
"The act post code must be an integer."
]
}
Explanation:
Unfortunately, it seems that nullable is only valid with certain other validations.
For example: 'act_post_code' => 'nullable|integer' will give you the error: "validation.integer"
However, 'act_post_code' => 'nullable|date' works fine.
Fix:
As a work around for these validations, you can make them dynamic. For example, before the validator:
$act_post_code_rules = $request->act_post_code ? 'integer' : '';
then, within the validate:
'act_post_code' => $act_post_code_rules
In order to validate the field act_post_code which can be either be of type integer or nullable, you can try out the following :
When declaring in the migration ,the Schema of the table where there is the column act_post_code declare the column like $table->integer('act_post_code')->nullable();
This one might just work for you to validate 'act_post_code' =>'sometimes|nullable|integer'
One can die and dump request parameters and check whether the actual value is null or "null" (in string). Sometimes when submitting a form via javascript we use FormData() to append data to the form, in those scenarios it may send a null value as in string type "null"
array:5 [
"firstName" => "Kaustubh"
"middleName" => "null" // null as string
"lastName" => "Bagwe"
"contactNumber" => null // null value
"photo" => null
"_method" => "PUT"
]
Open your migration file and make the this field as nullable
For e.g
Schema::create('your_table_name', function (Blueprint $table) {
$table->integer('act_post_code ')->nullable();
});
Make sure it is present in your model file in the fillable section
protected $fillable = ['act_post_code'];
After Some Test I found that nullable rule only work if only the data that we pass really was a null data.
so in my test case i use the validation rule like this :
"counter" => "nullable|numeric"
and in the blade file, I use Form::text('counter','') as element to input my data.
Then i use it with few test case:
When I input the counter data with a non-numeric value it will response with error: "the counter must be a number".
When I input the counter data with a numeric value it will pass the validation test.
When I not input any data to the counter it will pass the validation test.
so i check the data manually using dd($request_data)or if you using ajax just return $request_data and print it using console.log("data") like:
$.ajax({
type:'POST',
data:{_token:"{{ csrf_token() }}",
counter:$('input[name="counter"]').val()
},success:function(data){
console.log(data);
}
});
and found out that when input field is emptied it will give the null value.

ZF2 - different error messages with NotEmpty validator

I got stuck with this stupid error messages in Zend Framework 2. Spent two hours and nothing, I still got two different error messages with NotEmpty validator.
$nameNotEmptyMessage = 'Pole wymagane';
$inputFilter->add(array(
'name' => 'name',
'required' => true,
'filters' => array(
new Filter\StringTrim()
),
'validators' => array(
new Validator\NotEmpty(array(
'messages' => array(
Validator\NotEmpty::INVALID => $nameNotEmptyMessage,
Validator\NotEmpty::IS_EMPTY => $nameNotEmptyMessage
)
))
)
));
And what? It works pretty cool when I send form with "name" element inside it. When it's empty, I've got my message. But, when I send form without the "name" element inside it, the message is still "Value is required and can't be empty"! Why?
I need to have in both cases the same message because sometimes the form won't have "name" element.
Thank you guys very much!
Thanks for replying to the comment to clarify the problem. First I must say, I feel your pain on this one. After having not used ZF2 for over a year and spending some time figuring this out, it highlights yet another painful thing in ZF2.
That said, here is my simple solution. Not necessary correct, or the best way to go about it but it solves your problem with the least amount of code. In your controller where you instantiate and validate the form, add this code before you call new Form:
if (!isset($_POST['name'])) {
$this->getRequest()
->setPost(
new \Zend\Stdlib\Parameters(
array('name' => '')
)
);
}
This seemed the simplest route rather than setting up a default validation translator and adding a duplicate message. It is just checking to see if the name field was not present, and if so sets it with any empty value.
Now the reason why we have to do this:
This happens because of how \Zend\InputFilter\Input works. When the InputFilter runs, it sees the element is missing. It then checks the required property, sees it's true but the input has no value. No value being different than empty.
When the filter is required but has no input, \Zend\InputFilter\Input::prepareRequiredValidationFailureMessage is called. If you look at the source of that function, you'll see:
protected function prepareRequiredValidationFailureMessage()
{
$notEmpty = new NotEmpty();
$templates = $notEmpty->getOption('messageTemplates');
return [
NotEmpty::IS_EMPTY => $templates[NotEmpty::IS_EMPTY],
];
}
Notice how it creates a new NotEmpty validator and fetches its default message, thus bypassing the translation you set within the InputFilter.
The alternative:
One alternative, which may be more correct, but also requires more code and could arguably be more confusing looking back later would be to create a new class implementing \Zend\Validator\Translator\TranslatorInterface and set an array with the translation for that message and then calling \Zend\Validator\AbstractValidator::setDefaultTranslator passing that so the default translator will be used on that message.
This is just difficult because there is no short way of setting up that object because of how the classes are inherited and I wasn't able to find a quick solution to set up the default translator with just that message. Also, if you have another translator in place, it might interfere with it.
So it seems the simplest thing is to just check for the absence of that form field and populate it with any empty value if it's missing.
Hope that helps!
Other more simple way to fix this is to overwrite the Form setData($data) and to check if $data['name'] is set. Something like this:
public function setData($data)
{
if(!isset($data['name'])){
$data['name'] = '';
}
return parent::setData($data);
}

CakePHP Model::save allowed partially blank data during record insertion

I was investigating CakePHP (2.3.4) Model::save method to insert new records and ran into a little snag:
//Two fields provided, email field intended to fail validation
$data = array('Member' => array(
'username' => 'hello',
'email' => 'world'
));
$this->Member->create();
var_dump($this->Member->save($data, true));
The above save() will return false and no data will be written to the database. However if I change the data to:
//One field provided, intended to pass validation
$data = array('Member' => array(
'username' => 'hello'
));
then save() will attempt to write a new record to database with a blank email field. I realize that skipping validation for unspecified fields might be a useful behavior during updates, but is there a CakePHP recommended way to handle partially empty data sets when creating new records? Thanks a lot.
Edit:
Thanks to Sam Delaney for the tip. In case anybody else gets stumped, this did the trick: CakePHP Data Validation: field 'required' key
This key accepts either a boolean, or create or update. Setting this key to true will make the field always required. While setting it to create or update will make the field required only for update or create operations. If ‘required’ is evaluated to true, the field must be present in the data array. For example, if the validation rule has been defined as follows:
I had originally baked the model and forgotten that required => true was left out of the validation rule. Setting it to true or 'create' would've avoided me blank records getting inserted due to gibberish data array.
IMHO what you've experienced is the desired behavior. Consider that you have the same two fields within a form and the user provides a value for only username. Both username and email field are submitted even though email is empty. Then on the server, you try to save the record only to find out that it has failed validation which you feedback to the user. On the other hand, perhaps in your system it is perfectly possible to create a user without requiring an email (for example root access account), CakePHP's validation implementation allows both of these scenarios.
If this flexibility isn't what you desire, just set the required attribute for your validation rule as true:
public $validate = array(
'email' => array(
'rule' => 'email',
'required' => true
)
);
This will satisfy your all or nothing requirement.

Categories