Skip to content
Permalink
Browse files

Using another strategy for implementing notMatching in belongsToMany

After chaning the joins order, it was impossible to keep using the old way,
now it uses a NOT IN (subequery)
  • Loading branch information...
lorenzo committed Jun 23, 2016
1 parent 1dbaf17 commit 8266851d84a5e1027c2ab44caada6ca26e492481
Showing with 37 additions and 7 deletions.
  1. +1 −0 src/ORM/Association.php
  2. +36 −7 src/ORM/Association/BelongsToMany.php
@@ -575,6 +575,7 @@ public function attachTo(Query $query, array $options = [])
$dummy = $this
->find($finder, $opts)
->eagerLoaded(true);
if (!empty($options['queryBuilder'])) {
$dummy = $options['queryBuilder']($dummy);
if (!($dummy instanceof Query)) {
@@ -330,6 +330,11 @@ protected function _generateJunctionAssociations($junction, $source, $target)
*/
public function attachTo(Query $query, array $options = [])
{
if (!empty($options['negateMatch'])) {
$this->_appendNotMatching($query, $options);
return;
}
$junction = $this->junction();
$belongsTo = $junction->association($this->source()->alias());
$cond = $belongsTo->_joinCondition(['foreignKey' => $belongsTo->foreignKey()]);
@@ -363,14 +368,38 @@ public function attachTo(Query $query, array $options = [])
*/
protected function _appendNotMatching($query, $options)
{
$target = $this->junction();
if (!empty($options['negateMatch'])) {
$primaryKey = $query->aliasFields((array)$target->primaryKey(), $target->alias());
$query->andWhere(function ($exp) use ($primaryKey) {
array_map([$exp, 'isNull'], $primaryKey);
return $exp;
});
if (empty($options['negateMatch'])) {
return;
}
$options += ['conditions' => []];
$junction = $this->junction();
$belongsTo = $junction->association($this->source()->alias());
$conds = $belongsTo->_joinCondition(['foreignKey' => $belongsTo->foreignKey()]);
$subquery = $this->find()
->select(array_values($conds))
->where($options['conditions']);
$subquery = $options['queryBuilder']($subquery);
$assoc = $this->junction()->association($this->target()->alias());
$conditions = $assoc->_joinCondition([
'foreignKey' => $this->targetForeignKey()
]);
$subquery = $this->_appendJunctionJoin($subquery, $conditions);
$query->andWhere(function ($exp) use ($subquery, $conds) {
if (count($conds) === 1) {
return $exp->notIn(key($conds), $subquery);
}
return $this->_createTupleCondition(
$subquery,
array_keys($conds),
$subquery,
'NOT IN'
);
});
}
/**

0 comments on commit 8266851

Please sign in to comment.
You can’t perform that action at this time.