简体   繁体   中英

CakePHP 3 - How do you patch associated data manually, and save all?

I perform a find to retrieve one entity and contain one of its associated entities, of which it hasMany.

The retrieved data looks like this in simple terms:

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
        }
    ]
}

I want to manually modify fields on the main entity and fields on the contained entity.

I can modify the main entity easily like this:

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

The only way I could find of modifying the contained entity was to perform a separate patch on it. This can be done any number of ways. Here is one:

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

Then I want to save all:

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

The problem is the associated data does not get saved , and the reason is because $order->payment_instalments does not get marked as "dirty" because it was patched separately. So the only solution I found was to manually mark it as dirty:

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

Then the save will work.

This seems pretty messy to me, and would get a lot messier if I had to patch multiple contained entities. I couldn't find any documentation or help anywhere about how this is supposed to be done properly/elegantly.

Is there a way to modify both the main entity and contained entities in one go, and have it automatically recognise that the contained data is dirty?

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

The 0 => part is optional, of course, in this case. I've put it in there to make it more clear that the data is in a nested array.

The reason why it's only saving the order itself and not the associated record is here:

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

payment_instalments needs to be marked as dirty as well. That should happen automatically when you patch correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM