'Laravel 5 Eloquent, How to set cast attribute dynamically

In laravel 5.1 there is new feature called Attribute Casting, well documented at here : http://laravel.com/docs/5.1/eloquent-mutators#attribute-casting

My question is, it is possible to make attribute casting dynamically ?

for example, I have a table with columns :

id | name          | value       | type    |
1  | Test_Array    | [somearray] | array   |
2  | Test_Boolean  | someboolean | boolean |

it is possible to set value attribute cast, depends on type field, that work both in write(create/update) and fetch ?



Solution 1:[1]

The $casts attribute it used whenever you access a field, not when it is fetched from the database. Therefore, you can update the $casts attribute after the model has been populated, and it should work fine whenever you access the value field. You just need to figure out how to update the $casts attribute when the type field is changed.

One potential option would be to override the fill() method so that it calls the parent fill() method first, and then updates the $casts attribute with the data in the type field.

Another potential option would be to abuse the mutator functionality, and create a mutator on the type field, so that whenever it changes, it would update the $casts attribute.

Solution 2:[2]

Some of the answers here are really overthinking things, or they're subtly wrong.

The principle is simply to set the $casts property before you need it, eg. before writing or reading properties to the database.

In my case I needed to use a configured column name and cast it. Because PHP doesn't allow function calls in constant expressions, it can't be set in the class declaration, so I just declared my column/property's cast in my model's constructor.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model; 

class MyModel extends Model
{
    protected $casts = [
        // we can't call a function in a class constant expression or
        // we'll get 'Constant expression contains invalid operations'
        config('my-table.array-column.name') => 'array',
    ];

    public function __construct()
    {
        $this->casts = array_merge(
            $this->casts,
            [
                // my column name is configured so it isn't known at
                // compile-time so I have to set its cast run-time;
                // the model's constructor is as good a place as any
                config('my-table.array-column.name') => 'array',
            ]
        );

        parent::__construct(...func_get_args());
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 patricus
Solution 2 Joel Mellon