CakePHP 3 - Как вручную исправить связанные данные и сохранить все?

Я выполняю поиск, чтобы получить один объект и содержать один из связанных с ним объектов, которых у него много.

Полученные данные выглядят следующим образом:

object(App\Model\Entity\Order) {

    'id' => '67839',
    'price' => (int) 100,
    'payment_instalments' => [
        (int) 0 => object(Cake\ORM\Entity) {

            'id' => (int) 43150,
            'order_id' => '67839',
            'amount' => (int) 100
        }
    ]
}

Я хочу вручную изменить поля в основном объекте и поля вложенного объекта.

Я могу легко изменить основной объект следующим образом:

$order = $orders->patchEntity($order, [
    'price' => 200
]);

Единственный способ изменить содержащийся объект, который я смог найти, — это выполнить для него отдельный патч. Это можно сделать любым количеством способов. Вот один:

$instalments = TableRegistry::get('PaymentInstalments');
$instalment = $order->payment_instalments[0];
$order->payment_instalments[0] = $instalments->patchEntity(instalment , [
    'amount' => 200
]);

Затем я хочу сохранить все:

$orders->save($order, ['associated' => 'PaymentInstalments']);

Проблема заключается в том, что связанные данные не сохраняются, и причина в том, что $order->payment_instalments не помечается как "грязный", поскольку он был исправлен отдельно. Поэтому единственное решение, которое я нашел, — вручную пометить его как грязное:

$order->dirty('payment_instalments', true);

Тогда сейв сработает.

Мне это кажется довольно запутанным, и было бы намного запутаннее, если бы мне пришлось исправлять несколько содержащихся объектов. Я нигде не мог найти никакой документации или помощи о том, как это должно быть сделано правильно/элегантно.

Есть ли способ изменить как основной объект, так и содержащиеся объекты за один раз, чтобы он автоматически распознавал, что содержащиеся данные грязные?


person BadHorsie    schedule 27.01.2017    source источник


Ответы (1)


$order = $orders->patchEntity($order, [
    'price' => 123, // Change data on the order itself
    'payment_instalments' => [
        0 => [
            'id' => 43150,
            'amount' => 123,
        ]
    ]
]);

Часть 0 => в данном случае, конечно, необязательна. Я поместил его туда, чтобы было более понятно, что данные находятся во вложенном массиве.

Причина, по которой сохраняется только сам заказ, а не связанная запись, здесь:

'[dirty]' => [
    'price' => true
],

payment_instalments тоже нужно пометить как грязный. Это должно происходить автоматически при правильном патче.

person Greg Schmidt    schedule 27.01.2017
comment
Связанные данные уже находятся во вложенном массиве. Единственный способ, которым я мог заставить его работать, - вручную добавить $order->dirty('payment_instalments', true); Мои изменения не публикуются формой, я вручную изменяю данные, поэтому каков правильный способ исправления связанного объекта в этом случае (поскольку это не массив при выполнении поиска; это массив сущностей в payment_instalments). - person BadHorsie; 27.01.2017
comment
@BadHorsie Правильный способ показан здесь, в ответе, именно так вы бы это сделали. Тот факт, что исходное свойство содержит массив сущностей, не имеет значения, или, лучше сказать, это действительно необходимо для того, чтобы маршаллер мог правильно исправлять/объединять данные. - person ndm; 27.01.2017
comment
@BadHorsie, когда вы попробуете мой код, как будет выглядеть результат $order? Обратите внимание, что очень важно, чтобы id для связанной записи было включено в данные, которые вы передаете patchEntity, так как именно так он найдет объект, который необходимо исправить. - person Greg Schmidt; 27.01.2017
comment
@ndm Хорошо, я с тобой. Поэтому просто измените объекты, предоставив данные в формате массива, и маршаллер объединит их с объектами. - person BadHorsie; 28.01.2017