Изменение атрибута cast внутри коллекции в Laravel

У меня есть модель с атрибутом, который передается в массив, например

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

Мне нужно внести поправку в массив перед возвратом коллекции. Используя метод each в коллекции, я могу внести изменения в атрибуты внутри.

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

Это работает, и Коллекция изменена. Однако мне нужно изменить массив в атрибуте cast.

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

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

    }
});

Однако это возвращает ошибку.

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

Я понимаю, что для доступа к данным $ collection-> будет использоваться магия __get(), поэтому мне нужно будет использовать установщик. Итак, как мне этого добиться?

Заранее спасибо.


person DrKHunter    schedule 25.05.2016    source источник


Ответы (1)


Предположительно, вы можете взять весь массив, выполнить свои модификации, а затем установить его:

$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;

    }
});

Хотя, если эта модификация требуется для всех применений модели, возможно, было бы лучше сделать это в самой модели:

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

}
person Steve    schedule 25.05.2016
comment
Спасибо, это сработало. Я пробовал что-то подобное, но в этот момент другая часть кода была неправильной. - person DrKHunter; 25.05.2016
comment
Как бы вы добавили это в модель? В реальных данных больше логики, чем в этом примере. - person DrKHunter; 25.05.2016
comment
Что ж, вместо того, чтобы использовать массив $casts, чтобы позволить laravel обрабатывать приведение, вы можете использовать геттер (аксессор 1Attribute в языке laravel) для обработки приведения и любой другой логики: laravel.com/docs/5.1/eloquent-mutators - person Steve; 25.05.2016
comment
Спасибо. Затем мне также нужно было бы убедиться, что я закодировал в json при настройке данных. Разве этого тоже можно было добиться в модели? - person DrKHunter; 25.05.2016
comment
@DrKHunter Да, это можно сделать в модели с помощью установщика (мутатор атрибутов в документах), см. редактирование. - person Steve; 25.05.2016
comment
Хотя это приводит к очевидному вопросу о том, почему вы не сохраняете необходимые данные в первую очередь. Возможно, вам следует выполнить замену в сеттере (который будет вызываться намного реже при нормальных обстоятельствах) - person Steve; 25.05.2016
comment
Давайте продолжим обсуждение в чате. - person DrKHunter; 25.05.2016