2

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.

1 Answer 1

1

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);
    }

}
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you, that worked. I had tried something similar but at that point another part of the code was wrong.
How would you go about adding this to the model? There is more logic around the actual data than this example.
Well instead of using the $casts array to let laravel handle the cast, you can use a getter (1Attribute accessor in laravel speak) to handle the cast and any other logic: laravel.com/docs/5.1/eloquent-mutators
Thanks. I would then also need to make sure that I encoded to json when setting data. Unless this could also be achieved in the model?
@DrKHunter Yes, that can be done in the model with a setter (attribute mutator in docs), see edit.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.