Skip to content

Commit

Permalink
Refactor polymorphic feature
Browse files Browse the repository at this point in the history
  • Loading branch information
calebporzio committed Jan 31, 2019
1 parent 06bdd84 commit c14e901
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 119 deletions.
3 changes: 2 additions & 1 deletion src/HasParent.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ public function getClassNameForRelationships()

public function getMorphClass()
{
if ($this->parentHasHasChildrenTrait() && in_array(static::class, $this->getChildTypes())) {
if ($this->parentHasHasChildrenTrait()) {
$parentClass = $this->getParentClass();
return (new $parentClass)->getMorphClass();
}

return parent::getMorphClass();
}

Expand Down
152 changes: 34 additions & 118 deletions tests/Features/PolymorphismTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,163 +11,79 @@
class PolymorphismTest extends TestCase
{
/** @test */
public function morph_by_many()
public function parts_can_access_vehicles_with_morphed_by_many()
{
Vehicle::create()->parts()->create([]);
Car::create()->parts()->create([]);
Vehicle::create()->parts()->create();
Car::create()->parts()->create();

$parts = Part::with('vehicles')->get();
$parts = Part::all();

$vehicle = $parts->first()->vehicles->first();
$this->assertInstanceOf(Vehicle::class, $vehicle);

$car = $parts->last()->vehicles->first();

$this->assertInstanceOf(Vehicle::class, $vehicle);
$this->assertInstanceOf(Car::class, $car);

/** @var Part $part */
$part = Part::create();
$part->vehicles()->attach($vehicle);
$part->vehicles()->attach($car);

$part = Part::find($part->getKey());
$part->refresh();

$this->assertTrue($vehicle->is($part->vehicles()->first()));
$this->assertInstanceOf(Vehicle::class, $part->vehicles()->first());

$this->assertTrue($car->is($part->vehicles()->get()->pop()));
$this->assertInstanceOf(Vehicle::class, $part->vehicles()->first());
$this->assertInstanceOf(Car::class, $part->vehicles()->get()->pop());
}

/** @test */
public function can_query_where_has_one()
public function can_query_where_has_from_child_to_morphed()
{
$_1 = Part::create(['type' => 'tire']);
$_2 = Part::create(['type' => 'wing']);
$_3 = Part::create(['type' => 'engine']);
$_4 = Part::create(['type' => 'seat']);
$_5 = Part::create(['type' => 'some metal thing']);
$_6 = Part::create(['type' => 'i dont know car parts w/e']);

/** @var Car $car */
$car = Car::create([]);
/** @var Vehicle $vehicle */
$vehicle = Vehicle::create([]);

$car->parts()->attach($_1);
$car->parts()->attach($_2);
$car->parts()->attach($_3);

$vehicle->parts()->attach($_4);
$vehicle->parts()->attach($_5);
$vehicle->parts()->attach($_6);

$this->assertNull(Car::query()->whereHas('parts', function ($query) {
$query->where('type', 'seat');
})->first());

$checker = Vehicle::query()->whereHas('parts', function ($query) {
$notCar = Vehicle::create();
$car = Car::create();

$notCar->parts()->attach(Part::create(['type' => 'wing']));
$car->parts()->attach(Part::create(['type' => 'tire']));

$shouldNotBeCar = Car::query()->whereHas('parts', function ($query) {
$query->where('type', 'wing');
})->first();

$shouldBeCar = Vehicle::query()->whereHas('parts', function ($query) {
$query->where('type', 'tire');
})->first();

$this->assertNotNull($checker);
$this->assertTrue($car->is($checker));
$this->assertInstanceOf(Car::class, $checker);
$this->assertNull($shouldNotBeCar);
$this->assertTrue($car->is($shouldBeCar));
$this->assertInstanceOf(Car::class, $shouldBeCar);
}

/** @test */
public function can_query_where_has_two()
public function can_query_deeply_from_morphed_to_parental_models_via_where_has()
{
/** @var Part $part */
Part::create();
Part::create();
$part = Part::create();
Part::create();
$otherPart = Part::create();
Part::create();
/** @var Car $car */
$car = Car::create([]);
/** @var Vehicle $vehicle */
$vehicle = Vehicle::create([]);
$part->vehicles()->create([]);
$part->vehicles()->attach($vehicle);
$part->vehicles()->attach($car);
Part::create()->vehicles()->attach($car = Car::create());
$car->passengers()->create(['name' => 'Robert']);

$otherPart->vehicles()->create([]);
$otherPart->vehicles()->create([]);
$otherPart->vehicles()->create([]);
$otherPart->vehicles()->attach($vehicle);
$part = Part::whereHas('vehicles.passengers', function ($query) {
$query->where('name', 'Robert');
})->first();

$car->passengers()->create(['name' => 'Robert']);
$car->passengers()->create(['name' => 'Joe']);
$car->passengers()->create(['name' => 'John']);
$vehicle->passengers()->create(['name' => 'Bob']);
$vehicle->passengers()->create(['name' => 'Karl']);

$checker = Part::query()
->whereHas('vehicles.passengers', function ($query) {
$query->where('name', 'Robert');
})
->first();

$this->assertTrue($part->is($checker));

$checker = Part::query()
->whereHas('vehicles.passengers', function ($query) {
$query->where('name', 'Robert');
})
->with(['vehicles.passengers' => function ($query) {
$query->where('name', 'Robert');
}])
->first();

$this->assertTrue($car->is($checker->vehicles()->first()));
$this->assertEquals('Robert', $checker->vehicles()->first()->passengers()->first()->name);
$this->assertTrue($car->is($part->vehicles()->first()));
$this->assertEquals('Robert', $part->vehicles()->first()->passengers()->value('name'));
}

/** @test */
public function can_query_where_has_three()
public function can_query_deeply_from_parental_models_to_morphed_via_where_has()
{
/** @var Car $car */
$car = Car::create();
/** @var Vehicle $vehicle */
$vehicle = Vehicle::create();

$joe = Passenger::create(['name' => 'joe', 'vehicle_id' => $car->id]);
Passenger::create(['name' => 'john', 'vehicle_id' => $vehicle->id]);
Passenger::create(['name' => 'carl', 'vehicle_id' => $car->id]);
Passenger::create(['name' => 'tony', 'vehicle_id' => $vehicle->id]);
Passenger::create(['name' => 'robert', 'vehicle_id' => $car->id]);

$passenger = $car->passengers()->create(['name' => 'joe']);
$car->parts()->create(['type' => 'tire']);
$car->parts()->create(['type' => 'some']);
$car->parts()->create(['type' => 'type']);
$vehicle->parts()->create(['type' => 'and']);
$vehicle->parts()->create(['type' => 'some']);
$vehicle->parts()->create(['type' => 'other']);

// This already works today, but it's pretty ugly
$passenger = Passenger::query()->where(function ($query) {
$query->orWhereHas('car.parts', function ($query) {
$query->where('type', 'tire');
})->orWhereHas('vehicle.parts', function ($query) {
$query->where('type', 'tire');
});
})->first();

$this->assertNotNull($passenger);
$this->assertTrue($joe->is($passenger));
$this->assertTrue($car->is($passenger->vehicle));
$this->assertInstanceOf(Car::class, $passenger->vehicle);

unset($passenger);

// This works with the new version
$passenger = Passenger::query()->whereHas('vehicle.parts', function ($query) {
$query->where('type', 'tire');
})->first();

$this->assertNotNull($passenger);
$this->assertTrue($joe->is($passenger));
$this->assertTrue($passenger->is($passenger));
$this->assertTrue($car->is($passenger->vehicle));
$this->assertInstanceOf(Car::class, $passenger->vehicle);
}
Expand Down

0 comments on commit c14e901

Please sign in to comment.