Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/SingleInheritanceBuilderTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Nanigans\SingleTableInheritance;

use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Nanigans\SingleTableInheritance\Contracts\SingleTableInheritanceBuilder;

trait SingleInheritanceBuilderTrait
{
/**
* Returns a fresh instance of the model at the root of the inheritance-tree as defined by
* the Builder's `singleInheritanceRootModelClass` property.
* @return Model
*/
protected function newSingleInheritanceRootModel(): Model
{
$property = 'singleInheritanceRootModelClass';
if (!property_exists($this, $property)) {
throw new \RuntimeException(sprintf(
'%s must declare a string property named %s',
get_called_class(),
$property
));
}

$className = $this->$property;
return new $className();
}

/**
* This makes it so that polymorphic collections can be constructed properly.
*
* @param array|string $columns
* @return Model[]|static[]
*/
public function getModels($columns = ['*'])
{
/*
* The problem stems from Laravel using the first element in the collection to hydrate the rest of the records
* into Eloquent models. Thus, if any of the subsequent records do is of a type that does not inherit
* from that of the first element, then it fails.
*
* If we use an instance of the root model of the
* inheritance tree, then we can properly hydrate records into polymorphic models.
*/
$rootModel = $this->newSingleInheritanceRootModel();
return $rootModel->hydrate(
$this->query->get($columns)->all()
)->all();
}
}
7 changes: 6 additions & 1 deletion tests/Fixtures/Vehicle.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,9 @@ public function setPrimaryKey($primaryKey) {
public function setTable($table) {
$this->table = $table;
}
}

public function newEloquentBuilder($query)
{
return new VehicleBuilder($query);
}
}
13 changes: 13 additions & 0 deletions tests/Fixtures/VehicleBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Nanigans\SingleTableInheritance\Tests\Fixtures;

use Illuminate\Database\Eloquent\Builder;
use Nanigans\SingleTableInheritance\SingleInheritanceBuilderTrait;

class VehicleBuilder extends Builder
{
use SingleInheritanceBuilderTrait;

protected $singleInheritanceRootModelClass = Vehicle::class;
}
49 changes: 49 additions & 0 deletions tests/SingleTableInheritanceTraitCollectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Nanigans\SingleTableInheritance\Tests;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Nanigans\SingleTableInheritance\Exceptions\SingleTableInheritanceException;
use Nanigans\SingleTableInheritance\Tests\Fixtures\User;
use Nanigans\SingleTableInheritance\Tests\Fixtures\Bike;
use Nanigans\SingleTableInheritance\Tests\Fixtures\Car;
use Nanigans\SingleTableInheritance\Tests\Fixtures\MotorVehicle;
use Nanigans\SingleTableInheritance\Tests\Fixtures\Truck;
use Nanigans\SingleTableInheritance\Tests\Fixtures\Vehicle;

/**
* Class SingleTableInheritanceTraitQueryTest
*
* A set of tests for the behavior of Eloquent collections that are polymorphic.
*
* @package Nanigans\SingleTableInheritance\Tests
*/
class SingleTableInheritanceTraitCollectionTest extends TestCase {

public function testRefresh() {
(new MotorVehicle())->save();
(new Car())->save();
(new Truck())->save();
(new Truck())->save();
(new Bike())->save();

$results = Vehicle::all();

$this->assertEquals(5, count($results));

$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\MotorVehicle', $results[0]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Car', $results[1]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Truck', $results[2]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Truck', $results[3]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Bike', $results[4]);

$results = $results->fresh();

$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\MotorVehicle', $results[0]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Car', $results[1]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Truck', $results[2]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Truck', $results[3]);
$this->assertInstanceOf('Nanigans\SingleTableInheritance\Tests\Fixtures\Bike', $results[4]);
}
}