0

I'm trying to save associated data, but even though it seems to be set right it doesn't commit to the database. I have to explicitly use the associated table to save the data. using the 'associated' keyword is ineffective.

my controller action:

public function test_associated_save()
{
    $usersTable = TableRegistry::get('Users');
    $test_user = $usersTable->get(21, ['contain' => ['Names']]);
    $test_user['names'][0]['middle'] = 'test name';
    $usersTable->save($test_user);
    $usersTable->save($test_user, ['associated' => ['Names']]);
    debug($test_user);

    $test_user = $usersTable->get(21, ['contain' => ['Names']]);
    debug($test_user);

    $test_user['names'][0]['middle'] = 'test name';
    $namesTable = TableRegistry::get('Names');
    $namesTable->save($test_user['names'][0]);

    $test_user = $usersTable->get(21, ['contain' => ['Names']]);
    debug($test_user);
}

debug output for the two $test_user first debug

object(App\Model\Entity\User) {
    'id' => (int) 21,
     ...
    'names' => [
        (int) 0 => object(App\Model\Entity\Name) {
            'id' => (int) 20,
            'user_id' => (int) 21,
            'middle' => 'test name',
            ...
        '[accessible]' => [
         ...
         'middle' => true,
         ...
         ],
            '[dirty]' => [
                'middle' => true
            ],
            '[original]' => [
                'middle' => ''
            ],
            '[virtual]' => [],
            '[errors]' => [],
            '[repository]' => 'Names'
    },
    ...

second debug

object(App\Model\Entity\User) {
    'id' => (int) 21,
     ...
    'names' => [
        (int) 0 => object(App\Model\Entity\Name) {
            'id' => (int) 20,
            'user_id' => (int) 21,
            'middle' => '',
            ...
        '[accessible]' => [
         ...
         'middle' => true,
         ...
         ],
            '[dirty]' => [],
            '[original]' => [],
            '[virtual]' => [],
            '[errors]' => [],
            '[repository]' => 'Names'
    },
    ...

third debug

object(App\Model\Entity\User) {
    'id' => (int) 21,
     ...
    'names' => [
        (int) 0 => object(App\Model\Entity\Name) {
            'id' => (int) 20,
            'user_id' => (int) 21,
            'middle' => 'test name',
            ...
        '[accessible]' => [
         ...
         'middle' => true,
         ...
         ],
            '[dirty]' => [],
            '[original]' => [],
            '[virtual]' => [],
            '[errors]' => [],
            '[repository]' => 'Names'
    },
    ...

My Users table

class UsersTable extends Table
{
    public function initialize(array $config)
    {
        $this->table('users');
        $this->displayField('username');
        $this->primaryKey('id');
        $this->addBehavior('Timestamp');
        $this->hasMany('Names', [
            'foreignKey' => 'user_id'
        ]);
        ...
    }
    ...
}

My Names table

class NamesTable extends Table {

/**
 * Initialize method
 *
 * @param array $config The configuration for the Table.
 * @return void
 */
public function initialize(array $config)
{
    $this->table('names');
    $this->displayField('id');
    $this->primaryKey('id');
    $this->addBehavior('Timestamp');
    $this->belongsTo('Users', [
        'foreignKey' => 'user_id',
        'joinType' => 'INNER'
    ]);
}

my mysql tables

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) unsigned NOT NULL,
  `username` varchar(50) NOT NULL,
  ...
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `names` (
  `id` int(10) unsigned NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `middle` varchar(255) NOT NULL,
  ...
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8;
waspinator
  • 6,464
  • 11
  • 52
  • 78

1 Answers1

0

don't use array access to change object values. you can use patchEntity instead, after creating the changed data array.

    $test_data = [
      'names' => [
          [
             'id' => $test_user['names'][0]['id'],
             'middle' => 'test name 5' 
          ]
      ]
    ];
    $usersTable->patchEntity($test_user, $test_data);
waspinator
  • 6,464
  • 11
  • 52
  • 78
  • 1
    You can use array access or `Entity::set()`, but for nested data you will have to manually mark the propert(ies)y as dirty in most cases. http://book.cakephp.org/3.0/en/orm/saving-data.html#saving-associations – ndm Dec 30 '15 at 02:44
  • It seems to set the property as dirty when using array access, but it still doesn't save it. At least that's what it says in my debug output. – waspinator Dec 30 '15 at 02:56
  • ndm, I tried using set with the same results as array access. the fields are set to dirty like before, but aren't saved. making a data array and using patchEntity works. – waspinator Dec 31 '15 at 02:42
  • I'd somehow doubt that, `patchEntity()` internally uses `set()` and `dirty()` too, so I'm pretty sure that you're missing something, most likely the second half of my comment. – ndm Dec 31 '15 at 03:40