Laravel Mutators, Accessors - laravel

I've tried to implement mutators into my laravel 5.5. project since it looks like this would be the best way to auto-convert date object but for some reason it's not working. What i try to accomplish is to load a date object from mysql format Y-m-d and convert it to d.m.Y and write date objects with a format of d.m.Y to mysql with the format of Y-m-d. I get constantly errors like "delimiter not found" or "format error" etc.
protected $dateFormat = 'Y-m-d h:i';
protected $dates = [
'joined',
];
function getJoinedAttribute()
{
return $this->attributes['joined']->format('d.m.Y');
}
function setJoinedAttribute()
{
return $this->attributes['joined']->format('Y-m-d');
}

You sould use Carbon library to convert date.
Like this :
public function getDobAttribute($value)
{
return Carbon::parse($value)->format('d/m/Y');
}
public function setDobAttribute($value)
{
$this->attributes['dob'] = Carbon::createFromFormat('d/m/Y', $value)->toDateString();
}

Related

How to format timestamp data to date format in laravel

Hello I have laravel project that store data created_at as a timestamp, I would call it from database, but it still show timestamp format, how can I convert it to date format without changing my column type? image
here is my model:
public function getCreatedAtAttribute($value)
{
return Carbon::parse($value)->timestamp;
}
//fungsi untuk merubah format tanggal diubah ke timestamp
public function getUpdatedAtAttribute($value)
{
return Carbon::parse($value)->timestamp;
}
and how should I call it in view or .blade file??
Thank you
To convert to human readable string try changing your functions as below:
public function getCreatedAtAttribute($value)
{
return Carbon::parse($value)->toFormattedDateString();
}
//fungsi untuk merubah format tanggal diubah ke timestamp
public function getUpdatedAtAttribute($value)
{
return Carbon::parse($value)->toFormattedDateString();
}
toFormattedDateString() function will convert to format like Jun 22, 2020. See this article for more alternatives https://www.leonelngande.com/format-dates-for-humans-with-carbon-in-php/.
To use in blade file simply access the parameter like:
$modelvariablename->created_at
In your model:
public function getCreatedAtAttribute(): Carbon {
return Carbon::parse($this->created_at);
}
public function getUpdatedAtAttribute(): Carbon {
return Carbon::parse($this->created_at);
}
For use:
$model->created_at->format('d.m.Y');
If you pass the data from controller to blade You can call in your blade file like this ...
<sapn>{{ $variable->updated_at->toDateString() }}</span>
Or
<span>{{ $variable->updated_at->format('Y-m-d') }}</span>
if you want to convert to inside controller.
public function getCreatedAtAttribute($value)
{
return $value->toDateString();
}
fungsi untuk merubah format tanggal diubah ke timestamp
public function getUpdatedAtAttribute($value)
{
return $value->toDateString();
}
Or you can try carbon
use Carbon\Carbon;
public function getCreatedAtAttribute($value)
{
return Carbon::parse($value)->format('Y-m-d');
}
fungsi untuk merubah format tanggal diubah ke timestamp
public function getUpdatedAtAttribute($value)
{
return Carbon::parse($value)->format('Y-m-d');
}
I would suggest to use eloquent's attribute casting instead.
So for example, make created_at shown as date in d-m-Y format:
protected $casts = [
'created_at' => 'datetime:d-m-Y'
];
Note that attribute casting will only effects the attibute when the model is serialized to json or array (as stated in the doc).

How to convert unix timestamp to Carbon instance in Laravel in model itself?

What I have already:
Had this in model:
protected $dates = [ 'applied_date' ];
In database applied_date is stored in this format 2018-05-11 13:31:59.
so in view I can format it like below:
$applied_date->format('m/d/Y')
What I want:
In database applied_date is already stored in this format 1530205690 (unix timestamp).
I want to format in view like $applied_date->format('m/d/Y'), how can I achieve this?
Note:
We can do Carbon::createFromTimestamp($applied_date)->format('m/d/Y');
you can use laravel attributes https://laravel.com/docs/5.6/eloquent-mutators
something like this
/**
* Get formatted applied_date.
*
* #return string
*/
public function getDateAttribute()
{
$date = Carbon::createFromTimestamp($this->applied_date)->format('m/d/Y');
return $date;
}
then in you view you can do this {{ $model->date }}

Laravel set a common validator for all date fields in the system

I have different date fields in different models, I need to validate these date fields format on save of each model accordingly. is this possible?
Of course, you can. You just need to add this code below to your Model.
public static $rules = [
'date'=> 'reqired|date_format:MM:dd:YYYY' //if date is not required, ommite it
]
You can use different formats for your date in your different Models like MM:dd etc. Hope this helps you.
EDIT
To be able to use multiple date formats in a single validator You can define the multi-format date validation in your AppServiceProvider with the following code:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('date_multi_format', function($attribute, $value, $formats) {
// iterate through all formats
foreach($formats as $format) {
// parse date with current format
$parsed = date_parse_from_format($format, $value);
// if value matches given format return true=validation succeeded
if ($parsed['error_count'] === 0 && $parsed['warning_count'] === 0) {
return true;
}
}
// value did not match any of the provided formats, so return false=validation failed
return false;
});
}
}
You can later use this new validation rule like that:
'date' => 'date_multi_format:"Y-m-d H:i:s.u","Y-m-d"' //or any other format
Hope this helps, thanks.

timestampTz fields in Laravel

Laravel 5.4 supports the Postgres TIMESTAMP WITH TIME ZONE field type in migrations:
$table->timestampTz('scheduled_for');
Laravel can be set up to convert date fields (DATE, DATETIME, TIMESTAMP) into Carbon objects (and does so by default for the created_at and updated_at TIMESTAMP fields), but putting scheduled_for into the $dates field causes an error with the timezone-aware version:
InvalidArgumentException with message 'Trailing data'
Looking in the database and tinker, the field's value appears to be something like 2017-06-19 19:19:19-04. Is there a native way to get a Carbon object out of one of these field types? Or am I stuck using an accessor?
Resurrecting this question, hopefully with a helpful answer that gets accepted.
Laravel assumes a Y-m-d H:i:s database timestamp format. If you're using a Postgres timestampz column, that's obviously different. You need to tell Eloquent how to get Carbon to parse that format.
Simply define the $dateFormat property on your model like so:
Class MyModel extends Eloquent {
protected $dateFormat = 'Y-m-d H:i:sO';
}
Credit where credit is due: I found this solution in a GitHub issue
Put this inside your model
protected $casts = [
'scheduled_for' => 'datetime' // date | datetime | timestamp
];
Using $dates is more likely obsolete as $casts do the same stuff (maybe except $dateFormat attribute which can work only for $dates fields iirc, but I saw some complaining on it)
Edit
I was testing Carbon once on Laravel 5.4 and I created a trait for it
this is not production level code yet so include it in your model on your own risk
<?php namespace App\Traits;
use Carbon\Carbon;
trait castTrait
{
protected function castAttribute($key, $value)
{
$database_format = 'Y-m-d H:i:se'; // Store this somewhere in config files
$output_format_date = 'd/m/Y'; // Store this somewhere in config files
$output_format_datetime = 'd/m/Y H:i:s'; // Store this somewhere in config files
if (is_null($value)) {
return $value;
}
switch ($this->getCastType($key)) {
case 'int':
case 'integer':
return (int) $value;
case 'real':
case 'float':
case 'double':
return (float) $value;
case 'string':
return (string) $value;
case 'bool':
case 'boolean':
return (bool) $value;
case 'object':
return $this->fromJson($value, true);
case 'array':
case 'json':
return $this->fromJson($value);
case 'collection':
return new BaseCollection($this->fromJson($value));
case 'date':
Carbon::setToStringFormat($output_format_date);
$date = (string)$this->asDate($value);
Carbon::resetToStringFormat(); // Just for sure
return $date;
case 'datetime':
Carbon::setToStringFormat($output_format_datetime);
$datetime = (string)$this->asDateTime($value);
Carbon::resetToStringFormat();
return $datetime;
case 'timestamp':
return $this->asTimestamp($value);
default:
return $value;
}
}
/**
* Return a timestamp as DateTime object with time set to 00:00:00.
*
* #param mixed $value
* #return \Carbon\Carbon
*/
protected function asDate($value)
{
return $this->asDateTime($value)->startOfDay();
}
/**
* Return a timestamp as DateTime object.
*
* #param mixed $value
* #return \Carbon\Carbon
*/
protected function asDateTime($value)
{
$carbon = null;
$database_format = [ // This variable should also be in config file
'datetime' => 'Y-m-d H:i:se', // e -timezone
'date' => 'Y-m-d'
];
if(empty($value)) {
return null;
}
// If this value is already a Carbon instance, we shall just return it as is.
// This prevents us having to re-instantiate a Carbon instance when we know
// it already is one, which wouldn't be fulfilled by the DateTime check.
if ($value instanceof Carbon) {
$carbon = $value;
}
// If the value is already a DateTime instance, we will just skip the rest of
// these checks since they will be a waste of time, and hinder performance
// when checking the field. We will just return the DateTime right away.
if ($value instanceof DateTimeInterface) {
$carbon = new Carbon(
$value->format($database_format['datetime'], $value->getTimezone())
);
}
// If this value is an integer, we will assume it is a UNIX timestamp's value
// and format a Carbon object from this timestamp. This allows flexibility
// when defining your date fields as they might be UNIX timestamps here.
if (is_numeric($value)) {
$carbon = Carbon::createFromTimestamp($value);
}
// If the value is in simply year, month, day format, we will instantiate the
// Carbon instances from that format. Again, this provides for simple date
// fields on the database, while still supporting Carbonized conversion.
if ($this->isStandardDateFormat($value)) {
$carbon = Carbon::createFromFormat($database_format['date'], $value)->startOfDay();
}
// Finally, we will just assume this date is in the format used by default on
// the database connection and use that format to create the Carbon object
// that is returned back out to the developers after we convert it here.
$carbon = Carbon::createFromFormat(
$database_format['datetime'], $value
);
return $carbon;
}
}

Laravel: Change format of Carbon dates in models when converted to JSON

Currently, when I convert a model to JSON, all Carbon date fields are casted like so:
"end_time": {
"date": "2017-02-03 23:59:00.000000",
"timezone_type": 3,
"timezone": "Europe/London"
}
I want it casted using the Atom notation.
This can be done in carbon like so:
$order->end_time->toAtomString()
where $date is a Carbon date.
How can I make a model convert dates in the atom format when converting it to JSON?
I am aware that it is possible to append data like so: https://laravel.com/docs/5.3/eloquent-serialization#appending-values-to-json
But this does not change the format of an existing value?
With the risk of reviving a zombie, I shall present an alternate solution to this problem:
Override the serializeDate method defined by the trait HasAttributes:
/**
* Prepare a date for array / JSON serialization.
*
* #param \DateTimeInterface $date
* #return string
*/
protected function serializeDate(DateTimeInterface $date)
{
return $date->toAtomString();
}
The link you provided should be the solution for you as long as you are willing to use a different name than "end_time". You could append "end_time_formatted", or something similar.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
protected $appends = ['end_time_formatted'];
public function getEndTimeFormattedAttribute()
{
return $this->end_time->toAtomString();
}
}
Then any time you cast a model to json, it will include "end_time_formatted" with it.
Another option for you (if you require keeping the same name) would be to override the toJson method by copying it into your model. I'd probably advise against this, but it would prevent the need to say $this->created_at = $this->created_at->toAtomString() each time before you cast it to JSON.
/**
* Convert the model instance to JSON.
*
* #param int $options
* #return string
*
* #throws \Illuminate\Database\Eloquent\JsonEncodingException
*/
public function toJson($options = 0)
{
$atom = $this->created_at->toAtomString();
$json = json_encode($this->jsonSerialize(), $options);
if (JSON_ERROR_NONE !== json_last_error()) {
throw JsonEncodingException::forModel($this, json_last_error_msg());
}
$json = json_decode($json);
$json->created_at = $atom;
$json = json_encode($json);
return $json;
}
I wasn't able to get this to work by changing the value at the top of the method, so I was forced to json_decode, and then re-encode, which doesn't feel great to me. If you do use this route I'd suggest digging a little deeper to try get it working without the need to decode.
An alternative to use is to format your date which you receive from model
You could use a helper method which converts your date object to the format you wish using carbon.
Carbon facilitates formatting abilities and I feel this is what you are looking for :
your_function_name($created_at_date, $format = "jS M Y")
{
$carbon = new \Carbon\Carbon($created_at_date);
$formatted_date = $carbon->format($format);
return $formatted_date;
}
Hope this helps.

Resources