diff --git a/src/ColumnSortable/Exceptions/ColumnSortableException.php b/src/ColumnSortable/Exceptions/ColumnSortableException.php index 7b916d7..8ffc503 100644 --- a/src/ColumnSortable/Exceptions/ColumnSortableException.php +++ b/src/ColumnSortable/Exceptions/ColumnSortableException.php @@ -17,7 +17,7 @@ public function __construct($message = '', $code = 0, Exception $previous = null $message = 'Relation \''.$message.'\' does not exist.'; break; case 2: - $message = 'Relation \''.$message.'\' is not instance of HasOne or BelongsTo.'; //hasMany + $message = 'Relation \''.$message.'\' is not instance of HasOne, MorphOne, or BelongsTo.'; //hasMany break; } diff --git a/src/ColumnSortable/Sortable.php b/src/ColumnSortable/Sortable.php index 43dcc0f..778815b 100755 --- a/src/ColumnSortable/Sortable.php +++ b/src/ColumnSortable/Sortable.php @@ -5,6 +5,8 @@ use BadMethodCallException; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Database\Eloquent\Relations\MorphOne; +use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Facades\Schema; @@ -145,8 +147,13 @@ private function parseParameters(array $parameters) */ private function queryJoinBuilder($query, $relation) { + if ($relation instanceof MorphTo) { + throw new \Exception(); + } $relatedTable = $relation->getRelated()->getTable(); $parentTable = $relation->getParent()->getTable(); + $morphClass = $relation->getParent()->getMorphClass(); + $morphType = null; if ($parentTable === $relatedTable) { $query = $query->from($parentTable.' as parent_'.$parentTable); @@ -159,12 +166,16 @@ private function queryJoinBuilder($query, $relation) $parentPrimaryKey = $relation->getQualifiedParentKeyName(); } elseif ($relation instanceof BelongsTo) { $relatedPrimaryKey = $relation->getQualifiedOwnerKeyName(); - $parentPrimaryKey = $relation->getQualifiedForeignKeyName(); + $parentPrimaryKey = $relation->getQualifiedForeignKeyName(); + } elseif ($relation instanceof MorphOne) { + $relatedPrimaryKey = $relation->getQualifiedForeignKeyName(); + $parentPrimaryKey = $relation->getQualifiedParentKeyName(); + $morphType = $relation->getQualifiedMorphType(); } else { throw new \Exception(); } - return $this->formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey); + return $this->formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey, $morphType, $morphClass); } @@ -211,13 +222,24 @@ private function formatToParameters($array) * @param $relatedTable * @param $parentPrimaryKey * @param $relatedPrimaryKey + * @param $morphType + * @param $morphClass * * @return mixed */ - private function formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey) + private function formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey, $morphType = null, $morphClass = null) { $joinType = config('columnsortable.join_type', 'leftJoin'); - return $query->select($parentTable.'.*')->{$joinType}($relatedTable, $parentPrimaryKey, '=', $relatedPrimaryKey); + $query + ->select($parentTable.'.*') + ->{$joinType}($relatedTable, function ($join) use ($parentPrimaryKey, $relatedPrimaryKey, $morphType, $morphClass) { + $join->on($parentPrimaryKey, '=', $relatedPrimaryKey); + if (! is_null($morphType) && ! is_null($morphClass)) { + $join->where($morphType, '=', $morphClass); + } + }); + + return $query; } } diff --git a/tests/ColumnSortableTraitTest.php b/tests/ColumnSortableTraitTest.php index 97fe6ec..cb26ae2 100644 --- a/tests/ColumnSortableTraitTest.php +++ b/tests/ColumnSortableTraitTest.php @@ -30,6 +30,11 @@ class ColumnSortableTraitTest extends \Orchestra\Testbench\TestCase */ private $post; + /** + * @var \Image + */ + private $image; + /** * @var */ @@ -51,6 +56,7 @@ public function setUp(): void $this->profile = new Profile(); $this->comment = new Comment(); $this->post = new Post(); + $this->image = new Image(); $this->configDefaultDirection = 'asc'; } @@ -148,6 +154,16 @@ public function testSortableQueryJoinBuilder() $expectedQuery = $this->comment->newQuery()->from('comments as parent_comments')->select('parent_comments.*') ->leftJoin('comments', 'parent_comments.parent_id', '=', 'comments.id'); $this->assertEquals($expectedQuery->toSql(), $resultQuery->toSql()); + + $query = $this->user->newQuery()->with(['image']); + $relation = $query->getRelation('image'); + $resultQuery = $this->invokeMethod($this->user, 'queryJoinBuilder', [$query, $relation]); + $expectedQuery = $this->user->newQuery()->select('users.*')->leftJoin('images', function ($join) { + $join + ->on('users.id', '=', 'images.imageable_id') + ->where('images.imageable_type', '=', Image::class); + }); + $this->assertEquals($expectedQuery->toSql(), $resultQuery->toSql()); } @@ -350,6 +366,11 @@ public function addressSortable($query, $direction) { return $query->join('profiles', 'users.id', '=', 'profiles.user_id')->orderBy('address', $direction)->select('users.*'); } + + public function image() + { + return $this->morphOne(Image::class, 'imageable'); + } } /** @@ -417,4 +438,32 @@ class Post extends Model { use \Kyslik\ColumnSortable\Sortable; + + public function image() + { + return $this->morphOne(Image::class, 'imageable'); + } +} + +class Image extends Model +{ + + use \Kyslik\ColumnSortable\Sortable; + + public $sortable = [ + 'id', + 'name', + 'src', + 'altText', + 'created_at', + 'updated_at' + ]; + + /** + * @return \Illuminate\Database\Eloquent\Relations\MorphTo + */ + public function imageable() + { + return $this->morphTo(); + } }