Skip to content

Commit

Permalink
fix parent scope when parent implements DefaultsMissingAliasToParentC…
Browse files Browse the repository at this point in the history
…lass, and child models use global scopes
  • Loading branch information
wfeller committed Nov 15, 2019
1 parent 15dbde7 commit 8fe4360
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 10 deletions.
30 changes: 20 additions & 10 deletions src/ParentScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace WF\Parental;

use Closure;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
Expand All @@ -23,13 +24,13 @@ public function apply(Builder $builder, Model $parent) : void
}

$builder->where(function (Builder $builder) use ($parent) {
$childColumn = $parent->getInheritanceColumn();
$inheritanceColumn = $parent->getInheritanceColumn();

$existingImplementations = $parent->getGlobalScopes();

foreach (static::$registered[get_class($parent)] as $alias => $implementations) {
$builder->orWhere(function (Builder $builder) use ($alias, $childColumn, $implementations, $existingImplementations) {
$builder->where($childColumn, $alias);
$builder->orWhere(function (Builder $builder) use ($alias, $inheritanceColumn, $implementations, $existingImplementations) {
$builder->where($inheritanceColumn, $alias);

foreach ($implementations as $key => $implementation) {
if (Arr::has($existingImplementations, str_replace($alias.':', '', $key))) {
Expand All @@ -41,19 +42,28 @@ public function apply(Builder $builder, Model $parent) : void
});
}

$builder->orWhere(function (Builder $builder) use ($parent, $childColumn) {
$missingChildren = array_diff_key($parent->getChildTypes(), static::$registered[get_class($parent)]);
$builder->orWhereIn($childColumn, array_keys($missingChildren))
->orWhere($childColumn, $parent->getParentAlias())
->orWhereNull($childColumn);
});
if ($parent instanceof DefaultsMissingAliasToParentClass) {
$builder->orWhere(function (Builder $builder) use ($parent, $inheritanceColumn) {
$builder
->orWhereNotIn($inheritanceColumn, array_keys(static::$registered[get_class($parent)]))
->orWhereNull($inheritanceColumn);
});
} else {
$builder->orWhere(function (Builder $builder) use ($parent, $inheritanceColumn) {
$missingChildren = array_diff_key($parent->getChildTypes(), static::$registered[get_class($parent)]);
$builder
->orWhereIn($inheritanceColumn, array_keys($missingChildren))
->orWhere($inheritanceColumn, $parent->getParentAlias())
->orWhereNull($inheritanceColumn);
});
}
});
}

private function applyImplementation(Builder $builder, $implementation) : void
{
$builder->where(function (Builder $builder) use ($implementation) {
if ($implementation instanceof \Closure) {
if ($implementation instanceof Closure) {
($implementation)($builder);
} elseif ($implementation instanceof Scope) {
$implementation->apply($builder, $builder->getModel());
Expand Down
54 changes: 54 additions & 0 deletions tests/Features/ParentModelInheritsChildrenScopesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

namespace WF\Parental\Tests\Features;

use Illuminate\Foundation\Testing\WithFaker;
use WF\Parental\DefaultsMissingAliasToParentClass;
use WF\Parental\ParentScope;
use WF\Parental\Tests\Models\Car;
use WF\Parental\Tests\Models\InternationalTrip;
use WF\Parental\Tests\Models\LocalTrip;
use WF\Parental\Tests\Models\Plane;
use WF\Parental\Tests\Models\Train;
use WF\Parental\Tests\Models\Trip;
use WF\Parental\Tests\Models\Vehicle;
use WF\Parental\Tests\TestCase;

class ParentModelInheritsChildrenScopesTest extends TestCase
{
use WithFaker;

/** @test */
public function simple_scope_inheritance_check()
{
Expand Down Expand Up @@ -68,6 +77,18 @@ public function can_modify_query()
$this->assertInstanceOf(InternationalTrip::class, $trips->shift());
}

/** @test */
public function parent_scope_allows_all_types_if_types_default_to_parent_class()
{
$this->ensureVehicleHasParentScopeActive();

$this->createTenVehicles();

$this->assertInstanceOf(DefaultsMissingAliasToParentClass::class, new Vehicle);

$this->assertSame(10, Vehicle::query()->count());
}

private function createTenTrips()
{
Trip::query()->create(['duration' => 1]);
Expand All @@ -83,4 +104,37 @@ private function createTenTrips()
LocalTrip::query()->create(['duration' => 2]);
LocalTrip::query()->create(['duration' => 3]);
}

private function ensureVehicleHasParentScopeActive()
{
Car::addGlobalScope('test-scope', function ($q) {
$q->whereKeyNot(0);
});

$scopes = array_filter((new Vehicle)->getGlobalScopes(), function ($scope) {
return $scope instanceof ParentScope;
});

$this->assertCount(1, $scopes);
}

private function createTenVehicles()
{
Car::query()->create();
Car::query()->create();

Plane::query()->create();
Plane::query()->create();

Train::query()->create();

Vehicle::query()->create();
Vehicle::query()->create();

$inheritanceColumn = (new Vehicle)->getInheritanceColumn();

Vehicle::query()->create([$inheritanceColumn => $this->faker->jobTitle]);
Vehicle::query()->create([$inheritanceColumn => $this->faker->jobTitle]);
Vehicle::query()->create([$inheritanceColumn => $this->faker->jobTitle]);
}
}

0 comments on commit 8fe4360

Please sign in to comment.