saving belongsToMany association with same keys but different _joinData

限于喜欢 提交于 2021-01-29 05:56:56

问题


I have a belongsToMany relationship between two tables which is configured using a through table.

class UsersTable extends Table
{
   public function initialize(array $config)
   {
       $this->belongsToMany('Groups', [
           'through' => 'GroupsUsers',
       ]);
   }
}

class GroupsTable extends Table
{
   public function initialize(array $config)
   {
       $this->belongsToMany('Users', [
           'through' => 'GroupsUsers',
       ]);
   }
}

class GroupsUsersTable extends Table
{
   public function initialize(array $config)
   {
       $this->belongsTo('Groups');
       $this->belongsTo('Users');
   }
}

I can make associations between users and groups, but not I can't figure out how to make multiple associates between the same user and groups, but with different _joinData.

This is how the join table is built:

$table = $this->table('groups_users');

$table->addColumn('user_id', 'integer');
$table->addColumn('group_id', 'integer');
$table->addColumn('role', 'string');

$table->create();

When I add or edit a group by adding users to it, the $data in beforeMarshal() is

object(ArrayObject) {
    name => 'test group'
    users => [
        (int) 0 => [
            'id' => (int) 1,
            '_joinData' => [
                'role' => 'writer'
            ]
        ],
        (int) 1 => [
            'id' => (int) 1,
            '_joinData' => [
                'role' => 'editor'
            ]
        ]
    ]
}

after patching the entity in the controller with

$entity = $this->Groups->patchEntity(
    $entity,
    $data,
    ['associated' => ['Users._joinData']]
);

I get the following $entity in beforeSave()

object(App\Model\Entity\Group) {

    'id' => (int) 1,
    'name' => 'test group',
    'users' => [
        (int) 0 => object(App\Model\Entity\User) {

            'id' => (int) 1,
            'username' => 'testuser',
            '_joinData' => object(Cake\ORM\Entity) {

                'role' => 'writer',
                '[new]' => true,
                '[accessible]' => [
                    '*' => true
                ],
                '[dirty]' => [
                    'role' => true
                ],
                '[original]' => [],
                '[virtual]' => [],
                '[hasErrors]' => false,
                '[errors]' => [],
                '[invalid]' => [],
                '[repository]' => 'GroupsUsers'

            },
            '[new]' => false,
            '[accessible]' => [
                'username' => true,
                'groups' => true,
                '_joinData' => true
            ],
            '[dirty]' => [
                '_joinData' => true
            ],
            '[original]' => [
                '_joinData' => [
                    'role' => 'writer'
                ]
            ],
            '[hasErrors]' => false,
            '[errors]' => [],
            '[invalid]' => [],
            '[repository]' => 'Users'

        }
    ],

    '[new]' => false,
    '[accessible]' => [
        'name' => true,
        'users' => true
    ],
    '[dirty]' => [
        'users' => true,
        'modified' => true
    ],
    '[original]' => [
        'modified' => object(Cake\I18n\FrozenTime) {

            'time' => '2019-05-15T14:41:49+00:00',
            'timezone' => 'UTC',
            'fixedNowTime' => false

        }
    ],
    '[hasErrors]' => false,
    '[errors]' => [],
    '[invalid]' => [],
    '[repository]' => 'Groups'

}

So it looks like the Marshaller is removing the second "duplicate" user from the group, even though the _joinData is different. The default saveStrategy is replace, but manually changing it to append doesn't add the second association either.

How can I add the same user to the same group with different _joinData using the same join table.


回答1:


The marshaller uses the primary key to identify records, and the collection of existing entities will then only hold one user entity instance, so even though the marshaller will add the different join data sets, it will set it on one and the same entity... long story short, the marshaller isn't (yet) capable of doing what you're trying to do. You may want to open an issue over at GitHub if there isn't one already.

For now you'll have to save the records separately, for example like this (untested, but you get the idea):

$group = $this->Groups->patchEntity($entity, $data, [
    'fieldList' => ['name']
]);

$users = [];
foreach ($data['users'] as $userData) {
    $user = $this->Groups->Users->newEntity();
    $users[] = $this->Groups->Users->patchEntity($user, $userData);
}

$result = $this->Groups->getConnection()->transactional(function () use ($group, $users) {
    if (!$this->Groups->save($group, ['atomic' => false])) {
        return false;
    }

    if (!$this->Groups->Users->link($group, $users, ['atomic' => false])) {
        return false;
    }

    return true;
});


来源:https://stackoverflow.com/questions/56154557/saving-belongstomany-association-with-same-keys-but-different-joindata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!