使用相同的键但使用不同的_joinData保存EmiratesToMany关联

时间:2019-05-15 17:15:40

标签: cakephp orm associations has-and-belongs-to-many cakephp-3.7

我在两个表之间有一个belongsToMany关系,该关系是使用through表进行配置的。

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 = $this->table('groups_users');

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

$table->create();

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

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']]
);

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

}

因此,即使_joinData不同,看起来Marshaller也正在从组中删除第二个“重复”用户。默认的saveStrategyreplace,但是手动将其更改为append也不会添加第二个关联。

如何使用相同的联接表将同一用户添加到具有不同_joinData的同一组中。

1 个答案:

答案 0 :(得分:1)

封送处理程序使用主键标识记录,然后现有实体的集合将仅保存一个用户实体实例,因此,即使封送处理程序将添加不同的联接数据集,也会将其设置在一个相同的对象上实体...长话短说,编组员还没有能力做您想做的事情。如果还没有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;
});