Skip to content

Commit 825b2bf

Browse files
author
ChenCatherine
committed
Support MorphMany & MorphToMany
1 parent a18830f commit 825b2bf

11 files changed

+204
-2
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@
4141
},
4242
"minimum-stability": "dev",
4343
"prefer-stable": true
44-
}
44+
}

src/EloquentJoinBuilder.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationClause;
88
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationGlobalScope;
99
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationWhere;
10+
use Fico7489\Laravel\EloquentJoin\Relations\MorphManyJoin;
11+
use Fico7489\Laravel\EloquentJoin\Relations\MorphToJoin;
12+
use Fico7489\Laravel\EloquentJoin\Relations\MorphToManyJoin;
1013
use Illuminate\Database\Eloquent\Builder;
1114
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
1215
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
1316
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
1417
use Illuminate\Database\Eloquent\Relations\Relation;
1518
use Illuminate\Database\Eloquent\SoftDeletingScope;
1619
use Illuminate\Database\Query\JoinClause;
20+
use function PHPSTORM_META\type;
1721

1822
class EloquentJoinBuilder extends Builder
1923
{
@@ -199,7 +203,7 @@ private function performJoin($relations, $leftJoin = null)
199203

200204
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
201205
});
202-
} elseif ($relatedRelation instanceof HasOneJoin || $relatedRelation instanceof HasManyJoin) {
206+
} elseif ($relatedRelation instanceof HasOneJoin || $relatedRelation instanceof HasManyJoin) {
203207
$relatedKey = $relatedRelation->getQualifiedForeignKeyName();
204208
$relatedKey = last(explode('.', $relatedKey));
205209
$localKey = $relatedRelation->getQualifiedParentKeyName();
@@ -208,6 +212,47 @@ private function performJoin($relations, $leftJoin = null)
208212
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $currentTableAlias, $localKey) {
209213
$join->on($relatedTableAlias.'.'.$relatedKey, '=', $currentTableAlias.'.'.$localKey);
210214

215+
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
216+
});
217+
} elseif ($relatedRelation instanceof MorphManyJoin) {
218+
$relatedKey = $relatedRelation->getQualifiedForeignKeyName();
219+
$relatedKey = last(explode('.', $relatedKey));
220+
$localKey = $relatedRelation->getQualifiedParentKeyName();
221+
$localKey = last(explode('.', $localKey));
222+
$morphType = $relatedRelation->getMorphType();
223+
$morphClass = $relatedRelation->getMorphClass();
224+
225+
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $currentTableAlias, $localKey, $morphType, $morphClass) {
226+
$join->on($relatedTableAlias.'.'.$relatedKey, '=', $currentTableAlias.'.'.$localKey)
227+
->where($relatedTableAlias.'.'.$morphType, $morphClass);
228+
229+
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
230+
});
231+
} elseif ($relatedRelation instanceof MorphToManyJoin) {
232+
$relatedKey = $relatedRelation->getQualifiedRelatedPivotKeyName();
233+
$relatedKey = last(explode('.', $relatedKey));
234+
$foreignKey = $relatedRelation->getQualifiedForeignPivotKeyName();
235+
$foreignKey = last(explode('.', $foreignKey));
236+
$morphType = $relatedRelation->getMorphType();
237+
$morphClass = $relatedRelation->getMorphClass();
238+
$parentKey = $relatedRelation->getParentKeyName();
239+
$intermediateTableAlias = $relatedRelation->getTable();
240+
$joinIntermediateQuery = $intermediateTableAlias;
241+
242+
$this->$joinMethod($joinIntermediateQuery, function ($join) use (
243+
$relatedRelation, $relatedTableAlias, $intermediateTableAlias, $currentTableAlias,
244+
$relatedKey, $foreignKey, $parentKey, $morphType, $morphClass
245+
) {
246+
$join->on($intermediateTableAlias.'.'.$foreignKey, '=', $currentTableAlias.'.'.$parentKey)
247+
->where($intermediateTableAlias.'.'.$morphType, $morphClass);
248+
249+
$this->joinQuery($join, $relatedRelation, $intermediateTableAlias);
250+
})->$joinMethod($joinQuery, function ($join) use (
251+
$relatedRelation, $relatedTableAlias, $intermediateTableAlias, $currentTableAlias,
252+
$relatedKey, $foreignKey, $parentKey, $morphType, $morphClass
253+
) {
254+
$join->on($relatedTableAlias.'.'.$parentKey, '=', $intermediateTableAlias.'.'.$parentKey);
255+
211256
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
212257
});
213258
} else {

src/Relations/MorphManyJoin.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Relations;
4+
5+
use Fico7489\Laravel\EloquentJoin\Traits\JoinRelationTrait;
6+
use Illuminate\Database\Eloquent\Relations\MorphMany;
7+
8+
class MorphManyJoin extends MorphMany
9+
{
10+
use JoinRelationTrait;
11+
}

src/Relations/MorphToManyJoin.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Relations;
4+
5+
use Fico7489\Laravel\EloquentJoin\Traits\JoinRelationTrait;
6+
use Illuminate\Database\Eloquent\Relations\MorphMany;
7+
use Illuminate\Database\Eloquent\Relations\MorphToMany;
8+
9+
class MorphToManyJoin extends MorphToMany
10+
{
11+
use JoinRelationTrait;
12+
}

src/Traits/ExtendRelationsTrait.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
66
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
77
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
8+
use Fico7489\Laravel\EloquentJoin\Relations\MorphManyJoin;
9+
use Fico7489\Laravel\EloquentJoin\Relations\MorphToJoin;
10+
use Fico7489\Laravel\EloquentJoin\Relations\MorphToManyJoin;
811
use Illuminate\Database\Eloquent\Model;
912
use Illuminate\Database\Eloquent\Builder;
1013

@@ -24,4 +27,19 @@ protected function newHasMany(Builder $query, Model $parent, $foreignKey, $local
2427
{
2528
return new HasManyJoin($query, $parent, $foreignKey, $localKey);
2629
}
30+
31+
protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey)
32+
{
33+
return new MorphManyJoin($query, $parent, $type, $id, $localKey);
34+
}
35+
36+
protected function newMorphToMany(Builder $query, Model $parent, $name, $table,
37+
$foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey,
38+
$relationName = null, $inverse = false
39+
) {
40+
return new MorphToManyJoin($query, $parent, $name, $table,
41+
$foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey,
42+
$relationName = null, $inverse = false
43+
);
44+
}
2745
}

tests/Models/Category.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
4+
5+
class Category extends BaseModel
6+
{
7+
protected $table = 'categories';
8+
9+
protected $fillable = ['name'];
10+
11+
public function states()
12+
{
13+
return $this->morphedByMany(State::class, 'categorizable', 'categorizable', 'category_id');
14+
}
15+
}

tests/Models/Image.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
4+
5+
class Image extends BaseModel
6+
{
7+
protected $table = 'images';
8+
9+
protected $fillable = ['imageable_id', 'imageable_type'];
10+
11+
public function state()
12+
{
13+
return $this->morphTo('imageable');
14+
}
15+
}

tests/Models/State.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,14 @@ public function cities()
1616
{
1717
return $this->hasMany(City::class);
1818
}
19+
20+
public function categories()
21+
{
22+
return $this->morphToMany(Category::class, 'categorizable', 'categorizable');
23+
}
24+
25+
public function images()
26+
{
27+
return $this->morphMany(Image::class, 'imageable');
28+
}
1929
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
4+
5+
use Fico7489\Laravel\EloquentJoin\Tests\Models\Image;
6+
use Fico7489\Laravel\EloquentJoin\Tests\Models\State;
7+
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
8+
9+
class MorphManyTest extends TestCase
10+
{
11+
public function testMorphMany()
12+
{
13+
State::joinRelations('images')->get();
14+
15+
$queryTest = 'select states.*
16+
from "states"
17+
left join "images" on "images"."imageable_id" = "states"."id"
18+
and "images"."imageable_type" = ?
19+
where "states"."deleted_at" is null
20+
group by "states"."id"';
21+
22+
$this->assertQueryMatches($queryTest, $this->fetchQuery());
23+
}
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
4+
5+
use Fico7489\Laravel\EloquentJoin\Tests\Models\Image;
6+
use Fico7489\Laravel\EloquentJoin\Tests\Models\State;
7+
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
8+
9+
class MorphToManyTest extends TestCase
10+
{
11+
public function testMorphToMany()
12+
{
13+
State::joinRelations('categories')->get();
14+
15+
$queryTest = 'select states.*
16+
from "states"
17+
left join "categorizable" on "categorizable"."categorizable_id" = "states"."id"
18+
and "categorizable"."categorizable_type" = ?
19+
left join "categories" on "categories"."id" = "categorizable"."id"
20+
where "states"."deleted_at" is null
21+
group by "states"."id"';
22+
23+
$this->assertQueryMatches($queryTest, $this->fetchQuery());
24+
}
25+
}

tests/database/migrations/2017_11_04_163552_create_database.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,33 @@ class CreateDatabase extends Migration
1313
*/
1414
public function up()
1515
{
16+
Schema::create('categories', function (Blueprint $table) {
17+
$table->increments('id');
18+
$table->string('name')->nullable();
19+
20+
$table->timestamps();
21+
$table->softDeletes();
22+
});
23+
24+
Schema::create('categorizable', function (Blueprint $table) {
25+
$table->increments('id');
26+
$table->unsignedInteger('category_id')->nullable();
27+
$table->morphs('categorizable');
28+
29+
$table->foreign('category_id')->references('id')->on('categories');
30+
31+
$table->timestamps();
32+
$table->softDeletes();
33+
});
34+
35+
Schema::create('images', function (Blueprint $table) {
36+
$table->increments('id');
37+
$table->morphs('imageable');
38+
39+
$table->timestamps();
40+
$table->softDeletes();
41+
});
42+
1643
Schema::create('states', function (Blueprint $table) {
1744
$table->increments('id');
1845
$table->string('name')->nullable();

0 commit comments

Comments
 (0)