My model has the following validation and rules :
public $rules = [
'hire_date' => 'date|required|required_with:dismiss_date',
OR
'hire_date' => 'date_format:"Y-m-d"...',
];
protected $casts = [
//'hire_date' => 'date' ,
'dismiss_date' => 'date' ,
];
// Or
protected $dates = [
'hire_date'
];
If I cast the Hire Date or any other date field then it Throws an exception, as if the validation is not checking the format ; e.g 2017-08-AA
A two digit hour could not be found Data missing" on line 582 of
.....nesbot\carbon\src\Carbon\Carbon.php
If I remove the attribute casting for dates the validation works as expected and throws a validation exception. A workaround to keep the casting was to use mutators for all date fields
public function setHireDateAttribute ( $date )
{
$this->attributes['hire_date'] = TZ::isValidateDate($date) ? $date : null;
}
So my question is there something wrong with the setup ? if not what is the point of the date or date_format validations if I have to do it manually.
Related
Something good with laravel is "$casts" attribute. Exemple with dates :
protected $casts = [
'date_rec' => 'datetime:Y-m-d',
'date_liv' => 'datetime:Y-m-d',
];
It works well if you return result of eloquent's query.
But if you don't want return full object with all relations it's the hell.
Examples :
protected $casts = [
'date_rec' => 'datetime:Y-m-d',
'date_liv' => 'datetime:Y-m-d',
];
public function asListItem()
{
return [
"try_1" => $this->date_rec, // return : "2021-10-19T22:00:00.000000Z"
"try_2" => $this->date_rec->format('Y-m-d'), // return : "2021-10-19" or error/crash if date is null
"try_3" => substr($this->date_rec ?? '', 0, 10), // work always but boring
"try_4" => json_encode($this->date_rec) // infinite loading and then error timeout
];
}
Is it possible to define how I want laravel parse date globally at serialization ?
Thx
You can use Carbon::setToStringFormat('your format'); in your provider to set a default string format
I have a laravel nova panel like below. Im trying to use a Date field like below:
new Panel('Suggestions', [
Flexible::make('Suggestions')
->addLayout('Suggestions', 'suggestion', [
Text::make('Title'),
Textarea::make('Message'),
Date::make('Date', 'date')
])
->button('Add Suggestion'),
]),
However it shows this error:
{message: "Date field must cast to 'date' in Eloquent model.", exception: "Exception",…}
exception: "Exception"
file: "/var/www/html/vendor/laravel/nova/src/Fields/Date.php"
line: 41
message: "Date field must cast to 'date' in Eloquent model."
I have in the model the casts property like this:
protected $casts = [
'date' => 'date'
];
Do you know what can be the issue?
I don't have a date field on the database table relative to the model. I just have a suggestions json field that has a lot of columns including the "date" column/key, probably that's the issue. Do you know how to solve this issue in this scenario? Thanks
Add this to your casts instead of 'date' => 'date', this solved for me the issue.
protected $casts = [
'flexible-content' => FlexibleCast::class
];
Another options is resolving it and converting it to a MomentJS format which also works fine:
DateTime::make('Date')
->format('DD/MM/YYYY HH:mm')
->resolveUsing(function ($value) {
return $value;
}),
source: https://github.com/whitecube/nova-flexible-content/issues/171
First, I guess you need to rename your db field to something else.
And then
You need to cast your db field into your model like this:
//Casts of the model dates
protected $casts = [
'DB_FIELD_NAME' => 'date'
];
I'm using boostrap-datepicker, with "multiple-date" option activated.
My dates looks like this: [date1, date2, ...].
I'm also using an hidden input to retrieve an "id". This "id" help me to retrieve "startdate" and "enddate" inside my model.
So I'm looking for a validation rule who can tell me if my dates are valid and if they are inside two other dates that correspond to the "id" of my model.
For now my id and dates rules are like this:
$rules = [
'id' => 'required|numeric|exists:event,id,isactive,1',
'dates' => 'array'
]
You can do this in very simple manner like this
Here is the documentation about writing rules for before and after
protected $rules = array(
'afterdate' => 'after:'.$yourDateForm,
'beforedate' => 'before:'.$yourDateTo
);
Note :
You shall also extend your date validation like this
'start_date' => 'required|date|after:tomorrow'
'finish_date' => 'required|date|after:start_date'
Update :
As the OP wants to get the date from db,
You shall do like this
$yourStartDate = Call to get Start Date from Table;
$yourEndDate = Call to get End Date from Table;
and the rule shall be
$validator = Validator::make(
array('date' => $yourStartDate),
array('date' => 'after:'.$yourEndDate)
);
I have a user registration form which takes input birth day split in 3 different input fields i.e. day, month, year
{!! Form::selectMonth('month', null) !!}
{!! Form::selectRange('day', 1, 31, null) !!}
{!! Form::selectYear('year', Carbon\Carbon::now()->year, (new Carbon\Carbon('100 years ago'))->year, null) !!}
In the backend I have modified the Registrar.php/validator() to check the input date is a valid one:
public function validator(array $data) {
$data['date_of_birth'] = Carbon::create($data['year'], $data['month'], $data['day'], 0, 0, 0)->toDateString();
$current_year = Carbon::now()->year;
$hundred_years_ago = (new Carbon("100 years ago"))->year;
return Validator::make($data, [
'year' => 'Required|Integer|Between:'.$hundred_years_ago.','.$current_year,
'month' => 'Required|Integer|Between:1,12',
'day' => 'Required|Integer|Between:1,31',
'date_of_birth' => 'Required|Date',
]);
}
But surely it doesn't check if an invalid date was provided. If the user provides an invalid date such as 31st February, 1982, the Carbon::create() transforms the date to 3rd March, 1982 which turns out to be a valid one.
If I want to filter this type of date input what do I need to do? I do believe this is likely a very common requirement for those who don't use any datepicker of some sort.
Laravel using the strtotime and checkdate functions to validate a date.
How the validateDate function of Laravel works? An example:
strtotime('30-2-2015'); // returns a timestamp
checkdate(2, 30, 2015); // returns false
// laravel raises an error
Therefore, the value of $data['date_of_birth'] should be a string in a particular format.
public function validator(array $data)
{
$data['date_of_birth'] = $data['day'].'-'.$data['month'].'-'.$data['year'];
$current_year = Carbon::now()->year;
$hundred_years_ago = (new Carbon("100 years ago"))->year;
return Validator::make($data, [
'year' => 'Required|Integer|Between:'.$hundred_years_ago.','.$current_year,
'date_of_birth' => 'Required|Date',
]);
}
Also you can ignore the validation of day and month, since the date will be validated.
I want to validate two date fields in a form which is from_date and end_date. Need to check from_date is less than end_date.
$rules = array('from_date' => array('sometimes','date_format:"Y-m-d"', 'before:'.Input::get('to_date') ),
'to_date' => array('sometimes','date_format:"Y-m-d"', 'after:'.Input::get('from_date') ) );
This is what i tried. But that does not work. If i give the to_date as empty value it will through the error.
I know that it is a question about Laravel 4 BUT if you are using Laravel 5.3 now you can use something like:
$rules = array(
'date_start' => 'required|date_format:Y-m-d|before_or_equal:date_end',
'date_end' => 'required|date_format:Y-m-d|after_or_equal:date_start'
);
$validator = Validator::make($request->all(), $rules);
Please use the below code in laravel 5.2 and it works fine for validating start and end date.
$this->validate($request, [
'start_date' => 'required|before:end_date',
'end_date' => 'required',
]);
Laravel 5:
Here is more extensive approach that follows modern principles and is more Laravel-like. This is a little more complex but still easy to follow and the end results is much cleaner.
Let's start by changing a few things. Let's reduce this to the specific problem, use newer array syntax and apply formatting.
$rules = [
'from_date' => [
'before:'.Input::get('to_date') // This is what we will learn to do
],
'to_date' => [
'after:'.Input::get('from_date') // Do this one on your own
]
];
Now let's create a new Request with php artisan make:request StoreWhateverRequest. This will create the App/HTTP/Request/StoreWhateverRequest.php file. Open that and place your rules in the return array of the rules() function.
return [
'from_date' => 'date',
'to_date' => 'date|after_field:from_date'
];
This will not work yet because after_field isn't available to use yet. Let's create that. We need a new class that extends validator. You can place it in app/Services. We need something similar to:
<?php namespace App\Services;
use Illuminate\Validation\Validator;
use Carbon\Carbon;
class AfterFieldValidator extends Validator {
public function validateAfterField($attribute, $value, $parameters)
{
return Carbon::parse($value) > Carbon::parse($this->data[$parameters[0]]);
}
}
In the above we have: $attribute which is the name of the field we are checking (to_date), $value is the value of the field we are checking and $parameters is the parameters we passed to the Validator(from_date) seen in 'to_date' => 'date|afterField:from_date'. We also need the other data fields passed to the Validator, we can get these with $this->data. Then we just have to preform the logic appropriately. You really don't even need Carbon here but be sure to parse the string so we don't do string comparison.
Now we need to load this into the application. To do this put the below code inside the boot() function in app/Providers/AppServiceProviders.php.
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new afterFieldValidator($translator, $data, $rules, $messages);
});
The final step is easiest. Just inject and instance of StoreWhateverRequest into our Controller.
...
public function store(StoreWhateverRequest $request)
{
...
All done. I feel this is a pretty SOLID way to solve the problem.
Just came across this and thought I'd share an answer I found: Compare attributes in validation
Basically, you'd create a new Validator that extends Illuminate\Validation\Validator and write a custom rule in there:
public function validateEndAfter($attribute, $value, $parameters) {
$start_date = $this->getValue($parameters[0]); // get the value of the parameter (start_date)
return (strtotime($value) > strtotime($start_date));
}
then in your validator use the new rule:
$rules = [
'start_date' => 'required',
'end_date'=> 'required|end_after:start_date',
]
Anyhow,
I did as like this. So that even if any date in the form is empty that will auto fill and check the validation
$inputs = Input::all();
if(!empty($inputs))
{
$default_date_arr = array('from_date' => date('Y-m-d', strtotime('-1 days')), 'to_date' => date('Y-m-d'));
$inputs = $inputs+$default_date_arr;
}
$rules = array('from_date' => array('sometimes','date_format:"Y-m-d"', 'before:'.$to_date) ,
'to_date' => array('sometimes','date_format:"Y-m-d"', 'after:'.$from_date ) );
$validator = Validator::make($inputs,$rules);
if($validator->fails())
{ ... }
This may not be the answer for what i asked. But i needed just a way to finish this. May be will helpful for others.