Example #1
0
 /**
  * Add a condition over a related model.
  *
  * Usage:
  * ------
  *
  * There is different calling form for this function.
  *
  *  * Check existence of related models. This is a merely a WHERE EXISTS
  *  clause in SQL:
  *
  *      `$query->root('Blog')->has('articles');`
  *
  *  * Perform a condition over the *number* of related models:
  *
  *      `$query->root('Blog')->where('articles', '>', 100);`
  *
  *      This would retrieve blogs instance which contains at least one hundred
  *      articles.
  *
  *  * Use a Closure to add conditions to the subquery:
  *
  *      ```php
  *      $query->root('Blog')->has('articles', function ($q) {
  *          $q->where('online', true);
  *      });
  *
  * @param string $relation The name of the relation to check on.
  * @param string $op       Optional. The operator for the second use form.
  * @param mixed $value     Optional. The value for the second use form.
  *
  * @return $this
  */
 public function whereHas($relation, $op = null, $value = null, $not = false)
 {
     $mainQuery = $this->getQueryOrNewSelect();
     $mainQueryRootAlias = $mainQuery->getBuilder()->getRootAlias();
     // We'll use $rels for recursivity.
     $rels = explode('/', $relation);
     $relation = array_shift($rels);
     $root = $this->getRoot();
     $rel = $root::relation($relation);
     // We construct the sub-query. It can be the sub-query of an Exists
     // clause or a Count (if $op and $value are given).
     $subRootAlias = $this->getRootAlias();
     $subRootAlias = $subRootAlias ? $subRootAlias . '.' . $rel->name : $rel->name;
     $subQuery = new self($rel->lm->class, $subRootAlias);
     $subQuery->setConnection($this->getConnection());
     $subQuery->newSelect();
     $subQuery->whereRelation($rel, $mainQueryRootAlias);
     $subQuery->getQuery()->getCompiler()->useTableAlias = true;
     $mainQuery->getQuery()->getCompiler()->useTableAlias = true;
     if ($rels) {
         $relation = implode('/', $rels);
         $subQuery->whereHas($relation);
     }
     // We want a Count sub-query.
     if ($op !== null && $value !== null) {
         $subQuery->getQuery()->addAggregate('COUNT');
         $mainQuery->selectSub($subQuery->getQuery(), '#' . $relation);
         $mainQuery->where(DB::expr('#' . $relation), $op, $value, null, $not);
     } else {
         if ($op instanceof \Closure) {
             $op($subQuery);
         }
         $subQuery->get(array('*'), false);
         $mainQuery->whereExists($subQuery->getQuery(), null, $not);
     }
     return $this;
 }