基于自定义规则的 CakePHP3 过滤
CakePHP3 filtering based on custom rules
我有以下架构:
User hasMany RegistrationState
RegistrationState belongsTo User
到其经典的 1->M 关系,其中 user_id 在 RegistrationState table 中。
RegistrationState 具有以下属性
id, user_id, state, created_at ... ( others are not relevant )
用户可以有更多的注册状态例如:
Registration state -> 1, created -> 01-02-2017
Registration state -> 2, created -> 01-03-2017
Registration state -> 3, created -> 01-04-2017
Registration state -> 4, created -> 01-05-2017
Registration state -> 2, created -> 01-06-2017
Registration state -> 3, created -> 01-07-2017
我需要根据这个 'state property' 进行过滤,其中有效状态是最后创建的状态。
此示例的有效状态是 3,因为它是最新状态。
现在,我有控制器和 index 方法,我有
// push custom query for filtering to finder method
$this->paginate['finder'] = [
'clients' => ['q' => $this->request->query]
];
try {
$clients = $this->paginate( $this->Users );
} catch (\Exception $e) {
// redirect on main
return $this->redirect($this->here);
}
我的 finder 方法如下所示
public function findClients($query, array $options)
{
$opts = $query->getOptions()['q'];
if (!empty($opts['email'])) {
$query->andWhere(['email LIKE' => '%' . trim($opts['email']) . '%']);
}
if (!empty($opts['identity_num'])) {
$cn = $opts['identity_num'];
$query->matching('Identities', function ($query) use ($cn) {
$query->andWhere(['Identities.number' => $cn]);
});
}
// registration state
if (!empty($opts['reg_state'])) {
// WHAT SHOULD BE HERE???
}
return $query;
}
还有另一个 1->M 关系 User -> Identity,但是(匹配方法)但效果很好,因为数字始终是唯一的。
我无法解决注册状态的问题,如何在 CakePHP3 中实现这种搜索? (我不想破坏分页,所以我想在 finder 方法中解决这个问题)
一个可能的(肮脏的?)解决方案是子查询( RegistrationState 上的 INNER JOIN )
// registration state
if (!empty($opts['reg_state'])) {
$conn = ConnectionManager::get('default');
$subquery = $conn->execute(
'SELECT uir.user_id ' .
'FROM registration_state uir ' .
'INNER JOIN ( ' .
'SELECT user_id, max(created) as m_created ' .
'FROM registration_state ' .
'GROUP BY user_id ' .
') muir ON uir.user_id = muir.user_id AND uir.created = muir.m_created AND uir.status = '
. intval( $opts['reg_state'])
);
$usersInStateIds = [];
// transform result of subquery to usable array
foreach( $subquery->fetchAll('assoc') as $r ) {
$usersInStateIds[] = intval( $r['user_id'] );
}
$query->matching('RegistrationState', function ($query) use ($usersInStateIds) {
return $query->andWhere(['RegistrationState.user_id IN' => $usersInStateIds]);
});
}
我有以下架构:
User hasMany RegistrationState RegistrationState belongsTo User
到其经典的 1->M 关系,其中 user_id 在 RegistrationState table 中。
RegistrationState 具有以下属性
id, user_id, state, created_at ... ( others are not relevant )
用户可以有更多的注册状态例如:
Registration state -> 1, created -> 01-02-2017
Registration state -> 2, created -> 01-03-2017
Registration state -> 3, created -> 01-04-2017
Registration state -> 4, created -> 01-05-2017
Registration state -> 2, created -> 01-06-2017
Registration state -> 3, created -> 01-07-2017
我需要根据这个 'state property' 进行过滤,其中有效状态是最后创建的状态。
此示例的有效状态是 3,因为它是最新状态。
现在,我有控制器和 index 方法,我有
// push custom query for filtering to finder method
$this->paginate['finder'] = [
'clients' => ['q' => $this->request->query]
];
try {
$clients = $this->paginate( $this->Users );
} catch (\Exception $e) {
// redirect on main
return $this->redirect($this->here);
}
我的 finder 方法如下所示
public function findClients($query, array $options)
{
$opts = $query->getOptions()['q'];
if (!empty($opts['email'])) {
$query->andWhere(['email LIKE' => '%' . trim($opts['email']) . '%']);
}
if (!empty($opts['identity_num'])) {
$cn = $opts['identity_num'];
$query->matching('Identities', function ($query) use ($cn) {
$query->andWhere(['Identities.number' => $cn]);
});
}
// registration state
if (!empty($opts['reg_state'])) {
// WHAT SHOULD BE HERE???
}
return $query;
}
还有另一个 1->M 关系 User -> Identity,但是(匹配方法)但效果很好,因为数字始终是唯一的。
我无法解决注册状态的问题,如何在 CakePHP3 中实现这种搜索? (我不想破坏分页,所以我想在 finder 方法中解决这个问题)
一个可能的(肮脏的?)解决方案是子查询( RegistrationState 上的 INNER JOIN )
// registration state
if (!empty($opts['reg_state'])) {
$conn = ConnectionManager::get('default');
$subquery = $conn->execute(
'SELECT uir.user_id ' .
'FROM registration_state uir ' .
'INNER JOIN ( ' .
'SELECT user_id, max(created) as m_created ' .
'FROM registration_state ' .
'GROUP BY user_id ' .
') muir ON uir.user_id = muir.user_id AND uir.created = muir.m_created AND uir.status = '
. intval( $opts['reg_state'])
);
$usersInStateIds = [];
// transform result of subquery to usable array
foreach( $subquery->fetchAll('assoc') as $r ) {
$usersInStateIds[] = intval( $r['user_id'] );
}
$query->matching('RegistrationState', function ($query) use ($usersInStateIds) {
return $query->andWhere(['RegistrationState.user_id IN' => $usersInStateIds]);
});
}