Why associated data are always marked as new?

I use cakephp v3. I have an issue when saving associated entities that already exist in the database. For example I have an equipment which belongs to a constructor. When I edit an equipement by sending equipement data containing constructor data, the constructor is always detected as new even if I pass the constructor id.

Sended data to PUT http://api_url/equipment/:id
An equipement containing constructor data

Array
(	
	// ...
        [constructor] => Array
        (
            [id] => 105
            [corporate_name] => test
        )
	// ...
)

Model/Entity/Constructor.php
All fields are accessibles (so the id field should be correctly read)

class Constructor extends Entity
{
    // ...
    protected $_accessible = [
        'id' => true,
        '*'  => true
    ];
    // ...
}	

Controller/EquipmentController.php
Build the equipment entity before saving

public function edit($id) {
	// ...
	$equipment = $this->Equipments->get($id);
	$equipment = $this->patchEntity($equipment, $data, ['associated' => ['Constructors']]);
	// ...	
}

Display the entity
When I debug the entity before saving, the constructor ‘id’ field is marked as dirty and the constructor entity is marked as new.

// print_r($equipement)

App\Model\Entity\Equipment Object
(
    [id] => 2	
    [constructor] => App\Model\Entity\Constructor Object
        (
            [id] => 105
            [corporate_name] => test
            [[new]] => 1
            [[accessible]] => Array
                (
                    [id] => 1
                    [*] => 1
                )

            [[dirty]] => Array
                (
                    [id] => 1
                    [corporate_name] => 1
                )

            [[original]] => Array
                (
                )

            [[virtual]] => Array
                (
                )

            [[errors]] => Array
                (
                )

            [[repository]] => Constructors
        )
)    

But if I get the equipment like this :

Controller/EquipmentController.php
The equipment now explicitly contains the constructor data before patching

public function edit($id) {
	// ...
	$equipment = $this->Equipments->get($id, ['contain' => ['Constructors']]);
	$equipment = $this->patchEntity($equipment, $data, ['associated' => ['Constructors']]);
	// ...
}

Display the entity
The constructor is not detected as new anymore

// print_r($equipement)
App\Model\Entity\Equipment Object
(
    [id] => 2	
    [constructor] => App\Model\Entity\Society Object
        (
            [id] => 105
            [corporate_name] => test
            [[new]] => 
            [[accessible]] => Array
                (
                    [id] => 1
                    [*] => 1
                )

            [[dirty]] => Array
                (
                )

            [[original]] => Array
                (
                )

            [[virtual]] => Array
                (
                )

            [[errors]] => Array
                (
                )

            [[repository]] => Constructors
        )
)

Is this the normal behavior ? Do I need to load all associations with contain before patching the equipement entity ?

By the way I have the same issue when I create an new equipment with existing contractor which is very frustrating because I can’t load asociated data like in an edition. So existing data are validated like in creation mode and not in edition mode.

Thanks

This seems like the correct behavior to me, although I could be wrong I’ll provide a way to debug at the end.

When you specify the get command on the Equipment’s table CakePHP is retrieving only the data for the table row that has been selected. Because of this CakePHP has no idea of how the data is modeled, as far as it is concerned it’s updating the correct row within but the Entity object and does not contain the information for its association with Constructor. This would cause the Constructor to appear as dirty since CakePHP is not aware of it. Keep in mind the patchEntity method is performed by data provided by the Entity object, so data within the database is unknown. Assuming you were to then call the save method on the patched Entity, Cake would notice the association has already been made (it’s listed in the Entity object obtained from get) and skip it and only update the Equipments table (if any changes were made). This shouldn’t affect you in any major way but there is a performance penalty which I’ll discuss in a few.

Let’s now refer to when you call get with the contains option. In this scenario the Entity has both the Equipment’s row and all of its constructors associated rows. So when you call patchEntity, cakePHP has a direct comparison of what has been changed within the association and can better determine any modifications within the Constructors model. This explains why the dirty field is not filled when you specify ‘contain’. Calling the association with the contains option instructs allows CakePHP to inspect it as well when patchEntity is called.

Back to the performance penalty. You’re actually saving some performance when you specify the ‘contain’ option as cakephp can better determine if attempting to insert the Constructor object is worth it or not. That being said, your also losing performance because you are pulling a lot more information, so it’s really best to weigh your options depending on your needs. I’d say using ‘contains’ is the way to go since it will better assist CakePHP in differentiating the data. The penalty for pulling data should be salvaged if you are using a cache.

Again, I could be wrong but I’m 99.99% sure that this is what is going on within the applications logic. The best way to troubleshoot this would be to actually save the data within the database. Are you able to attempt saving the data within the database to see what happens? Or could you make a backup of the database and then try to save the result (you could restore the data in the worst case)?