a-dev-coder-f's avatar

Use Casts and Attribute (get) at the same time to set a value or return the casted value [Laravel 11]

I want to have a eloquent value casted to an array and use Attribute get at the same time to set a value depending on the results. Otherwise to just return the casted value as before

	protected $casts = [
 		'list' => 'array'
	]

    protected function list(): Attribute
    {
        // List might not be an array so force it become one
        return Attribute::make(
            get: fn ($value) => empty($value) ? [] : $value,
        );
    }

My list value could be something like false, 0, null and I want to convert it into an empty array before using it anywhere else in the laravel app. Otherwise it should continue being casted to an array. Or it being already casted, as false, 0, null would not be casted to an empty array without an attribute set.

It looks like the Attribute get actually overrides the cast itself. Where the $value is a raw value from the database and what you return is the final value. Of course I could transform the value into an array in the attribute itself, but I want use the casts as that makes things easier to maintain.

Is this possible?

0 likes
2 replies
Glukinho's avatar
Level 31

I think leaving only Attribute would be easier to maintain, because having both attribute and cast makes you look in two places when you want to know what is going in with the field.

Besides, you must always have in mind how cast and attribute affect each other.

Having only attribute is simple: all logic of this field is inside the attribute:

return Attribute::make(
    get: fn ($value) => empty($value) 
        ? [] 
        : json_decode($value),
);
1 like
a-dev-coder-f's avatar

@Glukinho In the most simple case, where I'm using Attribute get to transform the value to a default, then the double attribute, cast isn't confusing. Anything more than that then yeah, it'd get messy.

In my case, the database field is a string, so I needed to decode it so string 'false', '0' would be handled properly

        return Attribute::make(
            get: function (string $value) {
                $json = json_decode($value, true);

                // Invalid, empty, false, nulls become an empty array
                return is_array($json) ? $json : [];
            }
        );

Please or to participate in this conversation.