Commit 470d121b authored by Jens Segers's avatar Jens Segers

Adding has() functionality for hasMany and hasOne relations

parent 25a8bacf
<?php namespace Jenssegers\Eloquent;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\Relation;
use Jenssegers\Mongodb\Relations\HasOne;
use Jenssegers\Mongodb\Relations\HasMany;
use Jenssegers\Mongodb\Relations\BelongsTo;
use Jenssegers\Mongodb\Relations\BelongsToMany;
use Jenssegers\Mongodb\Relations\MorphTo;
......
<?php namespace Jenssegers\Mongodb\Eloquent;
use MongoCursor;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
class Builder extends \Illuminate\Database\Eloquent\Builder {
class Builder extends EloquentBuilder {
/**
* The methods that should be returned from query builder.
......@@ -14,6 +16,56 @@ class Builder extends \Illuminate\Database\Eloquent\Builder {
'count', 'min', 'max', 'avg', 'sum', 'exists', 'push', 'pull'
);
/**
* Add the "has" condition where clause to the query.
*
* @param \Illuminate\Database\Eloquent\Builder $hasQuery
* @param \Illuminate\Database\Eloquent\Relations\Relation $relation
* @param string $operator
* @param int $count
* @param string $boolean
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function addHasWhere(EloquentBuilder $hasQuery, Relation $relation, $operator, $count, $boolean)
{
$query = $hasQuery->getQuery();
// Get the number of related objects for each possible parent.
$relationCount = array_count_values($query->lists($relation->getHasCompareKey()));
// Remove unwanted related objects based on the operator and count.
$relationCount = array_filter($relationCount, function($counted) use ($count, $operator)
{
// If we are comparing to 0, we always need all results.
if ($count == 0) return true;
switch ($operator)
{
case '>=':
case '<':
return $counted >= $count;
case '>':
case '<=':
return $counted > $count;
case '=':
case '!=':
return $counted == $count;
}
});
// If the operator is <, <= or !=, we will use whereNotIn.
$not = in_array($operator, array('<', '<=', '!='));
// If we are comparing to 0, we need an additional $not flip.
if ($count == 0) $not = !$not;
// All related ids.
$relatedIds = array_keys($relationCount);
// Add whereIn to the query.
return $this->whereIn($this->model->getKeyName(), $relatedIds, $boolean, $not);
}
/**
* Create a raw database expression.
*
......
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany as EloquentHasMany;
class HasMany extends EloquentHasMany {
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query, Builder $parent)
{
$foreignKey = $this->getHasCompareKey();
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasOne as EloquentHasOne;
class HasOne extends EloquentHasOne {
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query, Builder $parent)
{
$foreignKey = $this->getHasCompareKey();
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
}
......@@ -303,4 +303,79 @@ class RelationsTest extends TestCase {
$this->assertInstanceOf('Client', $relations['imageable']);
}
public function testHasManyHas()
{
$author1 = User::create(array('name' => 'George R. R. Martin'));
$author1->books()->create(array('title' => 'A Game of Thrones', 'rating' => 5));
$author1->books()->create(array('title' => 'A Clash of Kings', 'rating' => 5));
$author2 = User::create(array('name' => 'John Doe'));
$author2->books()->create(array('title' => 'My book', 'rating' => 2));
User::create(array('name' => 'Anonymous author'));
Book::create(array('title' => 'Anonymous book', 'rating' => 1));
$authors = User::has('books')->get();
$this->assertCount(2, $authors);
$this->assertEquals('George R. R. Martin', $authors[0]->name);
$this->assertEquals('John Doe', $authors[1]->name);
$authors = User::has('books', '>', 1)->get();
$this->assertCount(1, $authors);
$authors = User::has('books', '<', 5)->get();
$this->assertCount(3, $authors);
$authors = User::has('books', '>=', 2)->get();
$this->assertCount(1, $authors);
$authors = User::has('books', '<=', 1)->get();
$this->assertCount(2, $authors);
$authors = User::has('books', '=', 2)->get();
$this->assertCount(1, $authors);
$authors = User::has('books', '!=', 2)->get();
$this->assertCount(2, $authors);
$authors = User::has('books', '=', 0)->get();
$this->assertCount(1, $authors);
$authors = User::has('books', '!=', 0)->get();
$this->assertCount(2, $authors);
$authors = User::whereHas('books', function($query)
{
$query->where('rating', 5);
})->get();
$this->assertCount(1, $authors);
$authors = User::whereHas('books', function($query)
{
$query->where('rating', '<', 5);
})->get();
$this->assertCount(1, $authors);
}
public function testHasOneHas()
{
$user1 = User::create(array('name' => 'John Doe'));
$user1->role()->create(array('title' => 'admin'));
$user2 = User::create(array('name' => 'Jane Doe'));
$user2->role()->create(array('title' => 'reseller'));
User::create(array('name' => 'Mark Moe'));
Role::create(array('title' => 'Customer'));
$users = User::has('role')->get();
$this->assertCount(2, $users);
$this->assertEquals('John Doe', $users[0]->name);
$this->assertEquals('Jane Doe', $users[1]->name);
$users = User::has('role', '=', 0)->get();
$this->assertCount(1, $users);
$users = User::has('role', '!=', 0)->get();
$this->assertCount(2, $users);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment