CakePHP 3 имеет много ассоциаций с побитовым выражением - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть две таблицы, AclGroups и AclPermissions, и я хочу создать между ними связь hasMany, т. Е. AclGroups имеет много AclPermissions.

Условие определения того, принадлежит ли группе данное разрешение, выполняется в одной побитовой проверке. Вот что я пытаюсь сделать:

SELECT 
    *
FROM
    acl_groups
        JOIN
    acl_permissions ON acl_permissions.permission & acl_groups.permission != 0

В AclGroupsTable Я пробовал следующее:

$this->hasMany('AclPermissions', [
    'className' => 'AclPermissions',
    'foreignKey' => 'permission',
    'conditions' => [
        'AclPermissions.permission & AclGroups.permission !=' => 0
    ]
]);

Но это только дает мне SQLSTATE[42S22]: Column not found: 1054 Unknown column 'aclgroups.permission' in 'where clause'

В моем контроллере я делаю:

$this->AclGroups->find('all')->contain(['AclPermissions']);

Полагаю, реальный вопрос заключается в следующем: есть ли способ изменить условия предложения ON в запросе, который выбирает связанные записи

1 Ответ

0 голосов
/ 12 сентября 2018

Как упоминалось в комментариях, записи hasMany ассоциаций (и belongsToMany в этом отношении) всегда будут извлекаться в отдельном запросе при использовании contain().

Если вам нужно создать объединения с такой связью, вы должны явно использовать соответствующие функции для объединений, например leftJoinWith():

$this->AclGroups->find('all')->leftJoinWith('AclPermissions');

Это создаст запрос, похожий на тот, который вы показываете. Однако он также будет генерировать условия по умолчанию, используя настроенный внешний ключ, вам придется отключить внешний ключ, чтобы избежать этого, например:

$this->hasMany('AclPermissions', [
    'foreignKey' => false, // << like this
    // ...
]);

Учитывая, что условия связывания не будут работать с contain() (а отключение внешнего ключа сделает его еще более непригодным для этой цели), вы можете создать отдельную связь для целей присоединения или использовать " методы соединения нижнего уровня, где вы указываете все условия вручную (вы можете, например, поместить это в пользовательский искатель, чтобы сохранить ваш код СУХИМЫМ):

$query = $this->AclGroups
    ->find('all')
    ->join([
        'table' => 'acl_permissions',
        'alias' => 'AclPermissions',
        'type' => 'LEFT',
        'conditions' => [
            'AclPermissions.permission & AclGroups.permission != :permission'
        ]
    ])
    ->bind(':permission', 0, 'integer');

Обратите внимание, что значение здесь явно связано, чтобы гарантировать, что используется правильный тип, так как его нельзя определить по нестандартному левому значению (которое на самом деле не содержит фрагментов SQL - вы может захотеть посмотреть на использование выражений).

Смотри также

...