Skip to content

Commit

Permalink
add nested relation support for related() method (#110)
Browse files Browse the repository at this point in the history
closes #105
  • Loading branch information
Tucker-Eric authored Dec 24, 2019
1 parent e6f9520 commit 7f6eb9c
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 15 deletions.
21 changes: 21 additions & 0 deletions src/ModelFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,30 @@ public function relationIsJoined($relation)
*/
public function getRelatedModel($relation)
{
if (strpos($relation, '.') !== false) {
return $this->getNestedRelatedModel($relation);
}

return $this->query->getModel()->{$relation}()->getRelated();
}

/**
* @param $relationString
* @return QueryBuilder|\Illuminate\Database\Eloquent\Model
*/
protected function getNestedRelatedModel($relationString)
{
$parts = explode('.', $relationString);
$related = $this->query->getModel();

do {
$relation = array_shift($parts);
$related = $related->{$relation}()->getRelated();
} while (! empty($parts));

return $related;
}

/**
* Get the table name from a relationship.
*
Expand Down
30 changes: 15 additions & 15 deletions tests/ModelFilterChildTest.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<?php

use EloquentFilter\TestClass\Client;
use EloquentFilter\TestClass\Location;
use EloquentFilter\TestClass\User;
use EloquentFilter\TestClass\UserFilter;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Schema\Builder as SchemaBuilder;
use Mockery as m;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -39,19 +38,11 @@ public function tearDown()

public function testGetRelatedModel()
{
$userMock = m::mock(User::class);
$userQueryMock = m::mock(Builder::class);
$hasManyMock = m::mock(HasMany::class);

$userQueryMock->shouldReceive('getModel')->once()->andReturn($userMock);

$userMock->shouldReceive('clients')->once()->andReturn($hasManyMock);

$hasManyMock->shouldReceive('getRelated')->once()->andReturn(new Client);

$client = (new UserFilter($userQueryMock))->getRelatedModel('clients');

$this->assertEquals($client, new Client);
$filter = new UserFilter($this->model->newQuery());
// Regular relation
$this->assertInstanceOf(Client::class, $filter->getRelatedModel('clients'));
// Nested relation
$this->assertInstanceOf(Location::class, $filter->getRelatedModel('clients.locations'));
}

public function testProvideFilter()
Expand All @@ -70,6 +61,12 @@ public function testGetModelFilterClass()
$this->assertEquals($this->model->getModelFilterClass(), EloquentFilter\TestClass\UserFilter::class);
}

public function testRelationDotNotation()
{
$users = $this->model->filter(['client_location' => 'one'])->get();
$this->assertEquals(1, $users->count());
}

public function testPaginationWorksOnBelongsToMany()
{
if (method_exists(\Illuminate\Database\Eloquent\Relations\Relation::class, 'macro')) {
Expand Down Expand Up @@ -130,7 +127,10 @@ protected function dbSetup()

$clients = [['name' => 'one'], ['name' => 'two'], ['name' => 'three'], ['name' => 'four']];
foreach ($clients as $index => $data) {
/** @var Client $client */
$client = Client::create($data);
$client->locations()->create($data);
/** @var User $user */
$user = User::create(['name' => 'Client'.$index]);
$user->clients()->save($client);
$client->managers()->save($user);
Expand Down
5 changes: 5 additions & 0 deletions tests/classes/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ public function managers()
{
return $this->belongsToMany(User::class);
}

public function locations()
{
return $this->hasMany(Location::class);
}
}
17 changes: 17 additions & 0 deletions tests/classes/Location.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace EloquentFilter\TestClass;

use Illuminate\Database\Eloquent\Model;

class Location extends Model
{
protected $fillable = ['name'];

public $timestamps = false;

public function client()
{
return $this->belongsTo(Client::class);
}
}
5 changes: 5 additions & 0 deletions tests/classes/UserFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ public function clientsSetup()
{
return $this;
}

public function clientLocation($location)
{
$this->related('clients.locations', 'name', $location);
}
}

0 comments on commit 7f6eb9c

Please sign in to comment.