Change date format before validation - laravel

I have to change the date format before validation.
I use the german date format (dd.mm.yyyy). But for the validation i need the format yyyy-mm-dd.
here my rules from the requests file:
public function rules()
{
return [
'title' => 'required|min:5',
'start' => 'required|date_format:d.m.Y|after:+1 week|unique:talks,start',
'end' => 'required|date_format:d.m.Y|after:start|unique:talks,end',
'interval' => 'required'
];
}
Now i found this function:
public function all()
{
$input = parent::all();
//modify input here
return $input;
}
But how can i modify the input here???
Thanks for your help

The $input variable is just an associative array with key -> value pairs of the request input. You can directly modify the array:
public function all()
{
$input = parent::all();
$input['start'] = date("Y-m-d", strtotime($input['start']));
$input['end'] = date("Y-m-d", strtotime($input['end']));
return $input;
}
This will translate your date values for the purposes of validation. Because the validator calls the all() method.
However, this does not modify the original values in your input.
Whenever you access the input values by a different method than all(), the original value will appear. E.g. $request->input('start') will give you the original German format but $request->all()['start'] will give you the translated international formal.
Such a situation is a potential source of bugs and it's hard to maintain. The right solution for your problem is to write a tiny custom middleware that will modify the request values. See here: https://laracasts.com/discuss/channels/general-discussion/laravel-5-modify-input-before-validation?page=2

Related

Laravel validation numeric with gte:1 throws exception

Why Laravel throws
InvalidArgumentException('The values under comparison must be of the same type');
exception, when input non-numeric text like 'test' on rule:
public function rules()
{
return [
'account_no' => 'required|numeric|gte:1'
];
}
When expected just not to pass validation and display message:
account_no field must be numeric
How to solve this exception?
Merdan the field under gte validation must be greater than or equal to the given field. The two fields must be of the same type.
example let's say you have two fields
POST DATA
// $request->comparison = 1;
// $request->account_no = 20319312;
your rules should be something like
return [
'account_no' => 'required|numeric|gte:comparison'
];
You have to use gte, the gt and gte are added in Laravel 5.6 and latest versions and I'm not sure what laravel version you are using.
I think you can try like this:
public function rules()
{
return [
'account_no' => 'required|numeric|min:1'
];
}
OR
public function rules()
{
return [
'account_no' => 'required|numeric|min:0|not_in:0'
];
}
The min:1 is the minimum value of 1 and no negative values are allowed
The not_in:0 is the value cannot be 0.
Also you can also use regular expression for doing this job.
I hope it would be helpful. Thanks

What is the correct order of form validation and retrieving input values?

I wonder if I should do form validation before retrieving input values or vice versa.
I usually do validation first as I see no benefit in trying to access input values that might not be valid. However, a coworker looked at my code recently and found it strange. Is there any correct order for these steps?
public function createGroups(Request $request)
{
$this->validate($request, [
'courses' => 'required_without:sections',
'sections' => 'required_without:courses',
'group_set_name' => 'required',
'group_number' => 'required|integer|min:1'
]);
$courses = $request->input('courses');
$sections = $request->input('sections');
$group_set_name = $request->input('group_set_name');
$group_number = $request->input('group_number');
Positioning the validation for your controller logic at the beginning of a method is probably the way to go here, as you have required parameters defined. If you receive data that does not fully satisfy the requirements, you produce a validation error back to the user. This follows the productive "Fail Fast" line of thinking: https://en.wikipedia.org/wiki/Fail-fast
It's also important that you're not using any data that hasn't passed your stringent requirements from validation. Data that fails validation should no longer be trusted. Unless there's some other reason you need to be, say, logging any incoming data from the frontend, the order here looks good to me.
I totally agree with #1000Nettles response, to elaborate a little bit more on his/her answer (who should be the accepted one): There isn't any need to continue with your business logic when the data doens't comply with your specifications. Let's say you expected a string of a N characters long, because you defined your database with that limitation (in order to optimize the db desing), will you try to persist it even when it'll throw an exception? Not really.
Besides, Laravel has a particular way to extract validation classes: Form Request. This are injected in controllers. When a call reach the controller it means that already passed the validation, if not, an 422error be returned.
Create a custom request and keep the mess out of your controller, it doesn't even hit your controller function if validation failed and can just grab the data in your controller if validation passed.
php artisan make:request GroupRequest
In app/Http/Requests/GroupRequest.php:
public function authorize()
{
// return true;
return request()->user()-isAdmin; // <-- example, but true if anyone can use this form
}
public function rules()
{
return [
'courses' => ['required_without:sections'],
'sections' => ['required_without:courses'],
'group_set_name' => ['required'],
'group_number' => ['required', 'integer', 'min:1'],
];
}
The best part is you can even manipulate the data in here (GroupRequest.php) after it has been validated:
public function validated()
{
$validated = $this->getValidatorInstance()->validate();
// EXAMPLE: hash password here then just use new hashed password in controller
$validated['password'] = Hash::make($validated['password']);
return $validated;
}
In your controller:
public function createUser(UserRequest $request) // <- in your case 'GroupRequest'
{
$validated = $request->validated(); // <-- already passed validation
$new_user = User::create($validated); // <-- password already hashed in $validated
return view('dashboard.users.show')->with(compact('user'));
}
In your case, if you use my GroupRequest block above, you can return to view in 1 line of code:
public function createGroups(GroupRequest $request)
{
return view('example.groups.show')->with($request->validated()); // <-- already an array
}
In you blade view file, you can then use your variables like {{ $group_set_name }} and {{ $group_number }}

Laravel Validation sometimes rules for date validation

I currently have a validation rule which looks like this:
public function rules()
{
return [
'startDate' => 'required|sometimes|before_or_equal:endDate',
'endDate' => 'sometimes|required|after_or_equal:startDate',
];
}
The sometimes option works as I understand it on the basis that if the field is present, run the validation rule. However, if the end date is not sent or is null, my before or equal rule kicks in and fails. In some instances within my application, end date will be null. Is there a way to 'cancel' the startDate validation rule in this instance or would I need to create a custom validator for this purpose?
something like before_or_equal_when_present ?
You can use IFs to add and manipulate rules in the rules function. You can access the inputs there referring to $this as the request itself:
public function rules()
{
$rules = [
'startDate' => 'required|sometimes|before_or_equal:endDate',
'endDate' => 'sometimes|required|after_or_equal:startDate',
];
if( $this->input('endDate') > 0)
$rules['endDate'] = "rule". $rules['endDate']
return $rules;
}
This is just a mockup just to let you know that you can manipulate and have access to the fields passed.

Yii2 compare email without case sensitive

I use the simple compare validation rule offered by Yii2 like this:
[confirm_email', 'compare', 'compareAttribute'=>'email', 'message'=>"Emails don't match"],
The problem is that this rule compares two emails 100% including Case Sensitive which means email#test.com and email#Test.com will generate validation error.
Is there a way to remove this Case Sensitive comparison from this rule?
strcasecmp does not handle multibyte characters, read this
suggestion is to use strtolower()
you might also be interested in yii's input filter, to transform input to lowercase, like this:
[
// both email fields tolower
[['email', 'confirm_email'], 'filter', 'filter' => 'strtolower'],
// normalize "phone" input
['phone', 'filter', 'filter' => function ($value) {
// normalize phone input here
return $value;
}], ]
You can create custom validation if you want.
public function rules()
{
return [
// an inline validator defined as the model method validateEmail()
['email', 'validateEmail'],
];
}
public function validateEmail($attribute, $params)
{
if (strcasecmp($this->attribute, $this->confirm_email) == 0) {
$this->addError($attribute, 'Username should only contain alphabets');
}
}
It will compare emails with binary safe case-insensitive.

Check if field exists in Input during validation using Laravel

I want to make sure that certain fields are posted as part of the form but I don;t mind if some are empty values.
The 'required' validation rule won't work as I am happy to accept empty strings. I have tried the below, but as the 'address2' field is never sent, the validator doesn't process it.
Any ideas?
$rules = array(
'address2' => 'attribute_exists'
);
class CustomValidator extends Illuminate\Validation\Validator {
public function validateAttributeExists($attribute, $value, $parameters)
{
return isset($this->data[$attribute]);
}
}
You can use Input::has('address2') to check if something is posted by address2 input name. See the example:
if(Input::has('address2')) {
// Do something!
}
In Laravel 5,
if($request->has('address2')){
// do stuff
}
You should make custom validator like this.
use Symfony\Component\Translation\TranslatorInterface;
class CustomValidator extends Illuminate\Validation\Validator {
public function __construct(TranslatorInterface $translator, $data, $rules, $messages = array())
{
parent::__construct($translator, $data, $rules, $messages);
$this->implicitRules[] = 'AttributeExists';
}
public function validateAttributeExists($attribute, $value, $parameters)
{
return isset($this->data[$attribute]);
}
}
This will make AttributeExists work without to use require. For more explain about this. When you want to create new validator rule. If you don't set it in $implicitRules, that method will not work out if you don't use require rule before it. You can find more info in laravel source code.
When you submit a form each and every field is posted, matter of fact is if you leave some filed empty then that field value is null or empty. Just check the POST parameters once, to do so open the firebug console in firefox and submit the form, then check the post parameters. As you want to accept empty string what is the use of any rule?
else You can do this
$addr2=Input::get('address2');
if(isset($addr2)){
//do here whatever you want
}else{
//do something else
$addr2='';//empty string
}
Actually, Laravel has a method to validate if an attribute exists even if not filled.
$rules = [
'something' => 'present'
];
All the validation rules are stored in Validator class (/vendor/laravel/framework/src/Illuminate/Validation/Validator.php), you can check for the implementation of each rule, even no documented rules.

Resources