保存具有相同键但不同_joinData 的 belongsToMany 关联

saving belongsToMany association with same keys but different _joinData

我在两个 table 之间有一个 belongsToMany 关系,它是使用 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');
   }
}

我可以在用户和组之间建立关联,但我不知道如何在同一个用户和组之间建立多个关联,但具有不同的_joinData

连接 table 的构建方式如下:

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

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

$table->create();

当我通过添加用户来添加或编辑群组时,beforeMarshal() 中的 $data

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

使用

修补控制器中的实体后
$entity = $this->Groups->patchEntity(
    $entity,
    $data,
    ['associated' => ['Users._joinData']]
);

我在 beforeSave()

中得到以下 $entity
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'

}

所以看起来 Marshaller 正在从组中删除第二个 "duplicate" 用户,即使 _joinData 不同。默认的 saveStrategyreplace,但手动将其更改为 append 也不会添加第二个关联。

如何使用相同的加入 table 将同一用户添加到具有不同 _joinData 的同一组。

编组器使用主键来识别记录,现有实体的集合将只包含一个用户实体实例,因此即使编组器将添加不同的连接数据集,它也会将其设置为一个和同一个实体......长话短说,编组器(还)不能做你想做的事。如果还没有,您可能想打开一个问题 over at GitHub

现在你必须单独保存记录,例如像这样(未经测试,但你明白了):

$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;
});