Skip to content

Commit

Permalink
Work on "has" method passing along constraints.
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Oct 31, 2013
1 parent e02bcae commit 7196279
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 14 deletions.
38 changes: 35 additions & 3 deletions src/Illuminate/Database/Eloquent/Builder.php
Expand Up @@ -587,15 +587,47 @@ protected function isNested($name, $relation)
*/ */
public function has($relation, $operator = '>=', $count = 1, $boolean = 'and') public function has($relation, $operator = '>=', $count = 1, $boolean = 'and')
{ {
$instance = $this->model->$relation(); $relation = $this->getHasRelationQuery($relation);


$query = $instance->getRelationCountQuery($instance->getRelated()->newQuery()); $query = $relation->getRelationCountQuery($relation->getRelated()->newQuery());


$this->query->mergeBindings($query->getQuery()); $this->mergeWheresToHas($query, $relation);


return $this->where(new Expression('('.$query->toSql().')'), $operator, $count, $boolean); return $this->where(new Expression('('.$query->toSql().')'), $operator, $count, $boolean);
} }


/**
* Merge the "wheres" from a relation query to a has query.
*
* @param \Illuminate\Database\Eloquent\Builder $hasQuery
* @param \Illuminate\Database\Eloquent\Relations\Relation $relation
* @return void
*/
protected function mergeWheresToHas(Builder $hasQuery, Relation $relation)
{
$relationQuery = $relation->getBaseQuery();

$hasQuery->mergeWheres($relationQuery->wheres, $relationQuery->getBindings());

$this->query->mergeBindings($relationQuery);
}

/**
* Get the "has relation" base query instance.
*
* @param string $relation
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function getHasRelationQuery($relation)
{
$me = $this;

return Relation::noConstraints(function() use ($me, $relation)
{
return $me->getModel()->$relation();
});
}

/** /**
* Add a relationship count condition to the query with an "or". * Add a relationship count condition to the query with an "or".
* *
Expand Down
22 changes: 21 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Expand Up @@ -740,7 +740,7 @@ public function detach($ids = array(), $touch = true)
* @return void * @return void
*/ */
public function touchIfTouching() public function touchIfTouching()
{ {
if ($this->touchingParent()) $this->getParent()->touch(); if ($this->touchingParent()) $this->getParent()->touch();


if ($this->getParent()->touches($this->relationName)) $this->touch(); if ($this->getParent()->touches($this->relationName)) $this->touch();
Expand Down Expand Up @@ -863,6 +863,16 @@ public function getRelatedFreshUpdate()
return array($this->related->getUpdatedAtColumn() => $this->related->freshTimestamp()); return array($this->related->getUpdatedAtColumn() => $this->related->freshTimestamp());
} }


/**
* Get the key for comparing against the pareny key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->getForeignKey();
}

/** /**
* Get the fully qualified foreign key for the relation. * Get the fully qualified foreign key for the relation.
* *
Expand All @@ -883,6 +893,16 @@ public function getOtherKey()
return $this->table.'.'.$this->otherKey; return $this->table.'.'.$this->otherKey;
} }


/**
* Get the fully qualified parent key naem.
*
* @return string
*/
protected function getQualifiedParentKeyName()
{
return $this->parent->getQualifiedKeyName();
}

/** /**
* Get the intermediate table for the relationship. * Get the intermediate table for the relationship.
* *
Expand Down
37 changes: 32 additions & 5 deletions src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
Expand Up @@ -36,25 +36,42 @@ public function __construct(Builder $query, Model $farParent, Model $parent, $fi
*/ */
public function addConstraints() public function addConstraints()
{ {
$this->setJoin($parentTable = $this->parent->getTable()); $parentTable = $this->parent->getTable();

$this->setJoin();


if (static::$constraints) if (static::$constraints)
{ {
$this->query->where($parentTable.'.'.$this->firstKey, '=', $this->farParent->getKey()); $this->query->where($parentTable.'.'.$this->firstKey, '=', $this->farParent->getKey());
} }
} }


/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query)
{
$this->setJoin($query);

return parent::getRelationCountQuery($query);
}

/** /**
* Set the join clause on the query. * Set the join clause on the query.
* *
* @param string $parentTable * @param \Illuminate\Databaes\Eloquent\Builder|null $query
* @return void * @return void
*/ */
protected function setJoin($parentTable) protected function setJoin(Builder $query = null)
{ {
$query = $query ?: $this->query;

$foreignKey = $this->related->getTable().'.'.$this->secondKey; $foreignKey = $this->related->getTable().'.'.$this->secondKey;


$this->query->join($parentTable, $this->getQualifiedParentKey(), '=', $foreignKey); $query->join($this->parent->getTable(), $this->getQualifiedParentKeyName(), '=', $foreignKey);
} }


/** /**
Expand Down Expand Up @@ -196,9 +213,19 @@ protected function getSelectColumns(array $columns = array('*'))
* *
* @return string * @return string
*/ */
protected function getQualifiedParentKey() protected function getQualifiedParentKeyName()
{ {
return $this->parent->getQualifiedKeyName(); return $this->parent->getQualifiedKeyName();
} }


/**
* Get the key for comparing against the pareny key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->farParent->getQualifiedKeyName();
}

} }
20 changes: 20 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php
Expand Up @@ -239,6 +239,16 @@ public function update(array $attributes)
return $this->query->update($attributes); return $this->query->update($attributes);
} }


/**
* Get the key for comparing against the pareny key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->getForeignKey();
}

/** /**
* Get the foreign key for the relationship. * Get the foreign key for the relationship.
* *
Expand Down Expand Up @@ -271,4 +281,14 @@ protected function getParentKey()
return $this->parent->getAttribute($this->localKey); return $this->parent->getAttribute($this->localKey);
} }


/**
* Get the fully qualified parent key naem.
*
* @return string
*/
protected function getQualifiedParentKeyName()
{
return $this->parent->getTable().'.'.$this->localKey;
}

} }
14 changes: 12 additions & 2 deletions src/Illuminate/Database/Eloquent/Relations/Relation.php
Expand Up @@ -136,9 +136,9 @@ public function getRelationCountQuery(Builder $query)
{ {
$query->select(new Expression('count(*)')); $query->select(new Expression('count(*)'));


$key = $this->wrap($this->parent->getQualifiedKeyName()); $key = $this->wrap($this->getQualifiedParentKeyName());


return $query->where($this->getForeignKey(), '=', new Expression($key)); return $query->where($this->getHasCompareKey(), '=', new Expression($key));
} }


/** /**
Expand Down Expand Up @@ -206,6 +206,16 @@ public function getParent()
return $this->parent; return $this->parent;
} }


/**
* Get the fully qualified parent key naem.
*
* @return string
*/
protected function getQualifiedParentKeyName()
{
return $this->parent->getQualifiedKeyName();
}

/** /**
* Get the related model of the relation. * Get the related model of the relation.
* *
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Database/Query/Builder.php
Expand Up @@ -1591,7 +1591,7 @@ public function newQuery()
*/ */
public function mergeWheres($wheres, $bindings) public function mergeWheres($wheres, $bindings)
{ {
$this->wheres = array_merge($this->wheres, (array) $wheres); $this->wheres = array_merge((array) $this->wheres, (array) $wheres);


$this->bindings = array_values(array_merge($this->bindings, (array) $bindings)); $this->bindings = array_values(array_merge($this->bindings, (array) $bindings));
} }
Expand Down
4 changes: 2 additions & 2 deletions tests/Database/DatabaseEloquentHasOneTest.php
Expand Up @@ -100,11 +100,11 @@ public function testRelationCountQueryCanBeBuilt()
$relation = $this->getRelation(); $relation = $this->getRelation();
$query = m::mock('Illuminate\Database\Eloquent\Builder'); $query = m::mock('Illuminate\Database\Eloquent\Builder');
$query->shouldReceive('select')->once()->with(m::type('Illuminate\Database\Query\Expression')); $query->shouldReceive('select')->once()->with(m::type('Illuminate\Database\Query\Expression'));
$relation->getParent()->shouldReceive('getQualifiedKeyName')->andReturn('foo'); $relation->getParent()->shouldReceive('getTable')->andReturn('table');
$query->shouldReceive('where')->once()->with('table.foreign_key', '=', m::type('Illuminate\Database\Query\Expression')); $query->shouldReceive('where')->once()->with('table.foreign_key', '=', m::type('Illuminate\Database\Query\Expression'));
$relation->getParent()->shouldReceive('getQuery')->andReturn($parentQuery = m::mock('StdClass')); $relation->getParent()->shouldReceive('getQuery')->andReturn($parentQuery = m::mock('StdClass'));
$parentQuery->shouldReceive('getGrammar')->once()->andReturn($grammar = m::mock('StdClass')); $parentQuery->shouldReceive('getGrammar')->once()->andReturn($grammar = m::mock('StdClass'));
$grammar->shouldReceive('wrap')->once()->with('foo'); $grammar->shouldReceive('wrap')->once()->with('table.id');


$relation->getRelationCountQuery($query); $relation->getRelationCountQuery($query);
} }
Expand Down

0 comments on commit 7196279

Please sign in to comment.