Search code examples
phplaravellaravel-collection

Amending a cast attribute inside a collection in Laravel


I have a model has an attribute which is cast to an array, like so

protected $casts = [
   'data' => 'array',
];

I need to make an amendment to the array before returning the Collection. Using the each method on the Collection I can make changes to the attributes inside.

$collection = $collection->each(function ($collection, $key) {
    if ($collection->type == 'foo') {
       $collection->type = 'bar';
    }
});

This works and the Collection is altered. However I need to change the array in the cast attribute.

$collection = $collection->each(function ($collection, $key) {
    if ($collection->type == 'foo') {

        foreach ($collection->data['x'] as $k => $v) {
            $collection->data['x'][$k]['string'] = 'example';
        }

    }
});

However this returns an error.

Indirect modification of overloaded property App\Models\Block::$data has no effect

I understand that accessing $collection->data will be using a magic __get() is being used, so I would need to use a setter. So how do I achieve this?

Thanks in advance.


Solution

  • Presumably you can take the whole array, perform your modifications and then set it:

    $collection = $collection->each(function ($collectionItem, $key) {
        if ($collectionItem->type == 'foo') {
            $data = $collectionItem->data;
            foreach ($data['x'] as $k => $v) {
                $data['x'][$k]['string'] = 'example';
            }
            $collectionItem->data = $data;
    
        }
    });
    

    Though if this modification is required for all uses of the model, perhaps it would be better to do this in the model its self:

    class SomeModel
    {
    
    
        //protected $casts = [
        //   'data' => 'array',
        //];
    
        public function getDataAttribute($value)
        {
            $data = json_decode($value);
            foreach ($data['x'] as $k => $v) {
                    $data['x'][$k]['string'] = 'example';
            }
            return $data;
        }
    
        public function setDataAttribute($value)
        {
            $this->attributes['data'] = json_encode($value);
        }
    
    }