Reputation: 8008
I'm using Laravel 5.1
I got a model:
class ExampleModel extends Model {
// ....
protected $dateFormat = 'Y.m.d';
protected $dates = ['first_date', 'second_date'];
// ...
}
So when I'm indexing ExampleModel elements, the date format is correct (ex 2015.07.31)
But on an edit form it uses the default format: 2015-07-31 00:00:00
I'm using Form::model()
binding.
I know I could use getFirstDateAttribute()
but it's not the solution I'm looking for. Because it's not elegant at all and once I defined the $dates
array, it should work automatically in every case.
So is it a bug maybe? Or am I doing something wrong?
Upvotes: 4
Views: 2938
Reputation: 547
I don't fully advise this as a fix because when you update the core you'll lose this fix, but maybe this should be posted as a pull request to Laravel's next version.
In \Illuminate\Database\Eloquent\Concerns\HasAttributes update the asDate function as follows. As you can see from the comments the asDate function still returns a timestamp even though it's 00:00:00.
/**
* Return a timestamp as DateTime object with time set to 00:00:00.
*
* @param mixed $value
* @return \Illuminate\Support\Carbon
*/
protected function asDate($value)
{
$date = $this->asDateTime($value)->startOfDay();
$date->setToStringFormat($this->getDateFormat());
return $date;
}
This allows you to control the format of a date from the model (note I'm differentiating between a date and datetime). Then use the casts variable to cast your variable to date format.
protected $casts = [
'start_date' => 'date',
'end_date' => 'date'
];
protected $dateFormat = 'Y-m-d';
The $dates variable cannot differentiate between a date and a datetime.
UPDATE The real problem is the form model binding skips the helper function of the FormBuilder class. As you can see if you inspect \Collective\Html\FormBuilder::date
/**
* Create a date input field.
*
* @param string $name
* @param string $value
* @param array $options
*
* @return \Illuminate\Support\HtmlString
*/
public function date($name, $value = null, $options = [])
{
if ($value instanceof DateTime) {
$value = $value->format('Y-m-d');
}
return $this->input('date', $name, $value, $options);
}
It is correctly formatting date to 'Y-m-d' as specified in HTML5 spec. However at this point $value is actually null. So you have to update the generic input function.
/**
* Create a form input field.
*
* @param string $type
* @param string $name
* @param string $value
* @param array $options
*
* @return \Illuminate\Support\HtmlString
*/
public function input($type, $name, $value = null, $options = [])
{
...
//$value is null here
if (! in_array($type, $this->skipValueTypes)) {
//$value is fetched based on hierarchy set by
$value = $this->getValueAttribute($name, $value);
//necessary duplicate code to format date value
if ($type == 'date' && $value instanceof DateTime) {
$value = $value->format('Y-m-d');
}
}
...
}
UPDATE There is no need to update vendor code. Check out FormModelAccessors
https://laravelcollective.com/docs/5.2/html#form-model-binding
Upvotes: 0
Reputation: 8008
I solved my problem by overriding Carbon's default date format:
Carbon\Carbon::setToStringFormat('Y.m.d');
But Kelly's answer is much better and more elegant, I just post this one as well, maybe someone will find this useful once.
Upvotes: 3
Reputation: 365
I've never done this before, but it seems to work on a basic example I put together. Note that I'm just calling the toArray
method on the model in the form opening tag.
{!! Form::model($exampleModel->toArray(), ['route' => ['example-models.update', $exampleModel->id]]) !!}
{!! Form::label('first_date', 'First Date') !!}
{!! Form::text('first_date') !!}
{!! Form::close() !!}
The docs say that the dateFormat
property determines the date format when the object is cast to json or an array.
Upvotes: 1