Ryan Taylor
Ryan Taylor

Reputation: 53

Laravel custom attribute not being mutated to Carbon date

I'm having problems getting Laravel to cast a custom attribute as a Carbon date. Here's an example model:

class Organisation extends Model
{
    protected $dates = [
        'my_date'
    ];

    public function getMyDateAttribute() 
    {
        return "2018-01-01 00:00:00";
    }
}

I'd expect my_date to be cast to a Carbon date however if I do dd($organisation->my_date) it just returns the date as a string.

I've seen people suggest to just return a Carbon instance from the custom attribute, and this partially works, the my_date attribute is availabe as a Carbon instance within the application, however if you then return the model as Json you end up with:

{
    "name": "Big Business",
    "my_date": {
        "date": "2018-01-01 00:00:00.000000",
        "timezone_type": 3,
        "timezone": "Europe/London"
    }
}

Instead of the desired:

{
    "name": "Big Business",
    "my_date": "2018-01-01 00:00:00"
}

Has anyone else come across this and if so have you found a solution?


Update

Upon further investigation I've tracked down the problem (but I don't have a solution yet). When you return an Eloquent model the __toString magic method which runs the toJson method and as you trace down the chain it serializes any Carbon dates in the $dates variable. It also completely skips over this serialization for mutated attributes, which is what I'm seeing.

I need to find a way to seralize mutated attributes that return a Carbon date when __toString is called.

Upvotes: 0

Views: 2874

Answers (2)

Jed Lynch
Jed Lynch

Reputation: 2156

You if your model represents a table, you can change the data type to timestamp and laravel will put that attribute into a carbon object.

Once the attribute is a carbon object, you can change the format in the blade view.

{{ $organisation->mydate->format('Y-m-d') }}

If either cannot change the data type, or you need to a default format different from a timestamp you can use the 'cast' eloquent model property.

class Organisation extends Model{

     protected $cast = [
         'mydate'=>'datetime:Y-m-d H:i:s'
     ];

 }

Casting the attribute effectively works the same as an accessor that wraps the date value with a carbon object. This is much cleaner way to write it, however.

As far as timezone is concerned, you should look to change that in the config/app.php file.

Here is the documentation.... https://laravel.com/docs/5.8/eloquent-mutators#attribute-casting

Upvotes: 0

Hussein
Hussein

Reputation: 1153

edit your Organization model to this:

use Carbon\Carbon;
class Organisation extends Model
{


    public function getMyDateAttribute($value) 
    {
        //you can manipulate the date here:
        $date = Carbon::parse($value,config('timezone'));
        return $date;
    }
}

Upvotes: 2

Related Questions