phpcakephpormcakephp-4.x

Associated data not being saved even though clearly changed


I cannot seem to be able to save associated data.

In my case, apparent changes to ServiceLineEntries can be seen, but aren't saved. Parent object (Requests) field is being saved and works as intended.

Output of code below:

starting at 4/10/24, 11:04 a.m.
project_manager: '', dirty: n
project_manager: 'Overflow, Stack', dirty: y
id: 24326, service_line_stage_id dirty: n
id: 24327, service_line_stage_id dirty: n
loop a - id: 24326, service_line_stage_id: 2, dirty: y
loop a - id: 24327, service_line_stage_id: 2, dirty: y
project_manager: 'Overflow, Stack'
loop b - id: 24326, service_line_stage_id: 1
loop b - id: 24327, service_line_stage_id: 1

Code:

public function myTest ()
{

    /*
    Requests Entity
        * @property \App\Model\Entity\ServiceLineEntry[] $service_line_entries

        protected $_accessible = [
            'service_line_entries' => true,
        ];

    Requests Table
        * @property \App\Model\Table\ServiceLineEntriesTable&\Cake\ORM\Association\HasMany $ServiceLineEntries

    ServiceLineEntries Entity

        protected $_accessible = [
        ...
        'service_line_stage_id' => true,
        ...
        ];

    ServiceLineEntries Table
        * @property \App\Model\Table\RequestsTable&\Cake\ORM\Association\BelongsTo $Requests
    */

    echo "starting at ".FrozenTime::now()."<br/>";

    //get record with association
    $request = $this->Requests->get(69311, [
        'contain' => [     
            'ServiceLineEntries',
        ],
    ]);

    //set project_manager
    echo "project_manager: '".$request->project_manager."', dirty: ".($request->isDirty('project_manager')?"y":"n")." <br/>";
    $request->project_manager = "Overflow, Stack";
    echo "project_manager: '".$request->project_manager."', dirty: ".($request->isDirty('project_manager')?"y":"n")." <br/>";

    //set service_line_stage_id
    foreach($request->service_line_entries as &$e)
    {
        echo "id: ".$e->id.", service_line_stage_id dirty: ".($e->isDirty('service_line_stage_id')?"y":"n")."</br>";
        $e->service_line_stage_id = 2;
        unset($e);
        //$e->setDirty('service_line_stage_id', true); doesn't help, isDirty() later seems to be true
    }

    //display value
    foreach($request->service_line_entries as $e)
    {
        echo "loop a - id: ".$e->id.", service_line_stage_id: ".$e->service_line_stage_id.", dirty: ".($e->isDirty('service_line_stage_id')?"y":"n")."</br>";
    }

    //save
    if($this->Requests->save($request, ['associated' => ['ServiceLineEntries']]))
    {
        //fetch fresh record with association
        $request2 = $this->Requests->get(69311, [
            'contain' => [     
                'ServiceLineEntries',
            ],
        ]);
        
        //display
        echo "project_manager: '".$request->project_manager."'<br/>";
        foreach($request2->service_line_entries as $e)
        {
            echo "loop b - id: ".$e->id.", service_line_stage_id: ".$e->service_line_stage_id."</br>";
        }
    }

    //no view, quit
    exit;
}

Solution

  • It seems like the changes to the ServiceLineEntries associated data are not being saved. To ensure the changes are tracked and saved properly, you need to manually mark the property that holds the nested entities as dirty. In this case, you can use $request->setDirty('service_line_entries', true); before saving the Requests entity with associated ServiceLineEntries. This will help CakePHP ORM track the changes and save them correctly.