Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e9edd6f

Browse files
author
admin
committedApr 14, 2020
Add support belongsToMany
1 parent ae94319 commit e9edd6f

13 files changed

+141
-12
lines changed
 

‎src/EloquentJoinBuilder.php

+35-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationGlobalScope;
1010
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationWhere;
1111
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
12+
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToManyJoin;
1213
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
1314
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
1415
use Illuminate\Database\Eloquent\Builder;
@@ -170,27 +171,32 @@ protected function performJoin($relations, $leftJoin = null)
170171
$currentTableAlias = $baseTable;
171172

172173
$relationsAccumulated = [];
173-
foreach ($relations as $relation) {
174-
if ($relation == $column) {
175-
//last item in $relations argument is sort|where column
176-
break;
177-
}
174+
for ($i = 0; $i < count($relations) - 1; ++$i) {
175+
$relation = $relations[$i];
176+
$nextRelation = $relations[$i + 1];
178177

179178
/** @var Relation $relatedRelation */
180179
$relatedRelation = $currentModel->$relation();
181180
$relatedModel = $relatedRelation->getRelated();
182181
$relatedPrimaryKey = $relatedModel->getKeyName();
183182
$relatedTable = $relatedModel->getTable();
184-
$relatedTableAlias = $this->useTableAlias ? sha1($relatedTable) : $relatedTable;
185183

186-
$relationsAccumulated[] = $relatedTableAlias;
184+
$relationsAccumulated[] = $relatedTable;
187185
$relationAccumulatedString = implode('_', $relationsAccumulated);
188186

187+
$relatedTableAlias = $this->useTableAlias ? sha1($relatedTable) : $relatedTable;
188+
189189
//relations count
190190
if ($this->appendRelationsCount) {
191191
$this->selectRaw('COUNT('.$relatedTableAlias.'.'.$relatedPrimaryKey.') as '.$relationAccumulatedString.'_count');
192192
}
193193

194+
if ($relatedRelation instanceof BelongsToManyJoin) {
195+
$pivotTable = $relatedRelation->getTable();
196+
$pivotTableAlias = $this->useTableAlias ? sha1($pivotTable) : $pivotTable;
197+
$joinQueryPivot = $pivotTable.($this->useTableAlias ? ' as '.$pivotTableAlias : '');
198+
}
199+
194200
if (!in_array($relationAccumulatedString, $this->joinedTables)) {
195201
$joinQuery = $relatedTable.($this->useTableAlias ? ' as '.$relatedTableAlias : '');
196202
if ($relatedRelation instanceof BelongsToJoin) {
@@ -212,13 +218,35 @@ protected function performJoin($relations, $leftJoin = null)
212218
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $currentTableAlias, $localKey) {
213219
$join->on($relatedTableAlias.'.'.$relatedKey, '=', $currentTableAlias.'.'.$localKey);
214220

221+
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
222+
});
223+
} elseif ($relatedRelation instanceof BelongsToManyJoin) {
224+
$localPivotKey = $relatedRelation->getForeignPivotKeyName();
225+
$relatedPivotKey = $relatedRelation->getRelatedPivotKeyName();
226+
$localKey = $relatedRelation->getParentKeyName();
227+
$relatedKey = $relatedRelation->getRelatedKeyName();
228+
229+
$this->$joinMethod($joinQueryPivot, function ($join) use ($relatedRelation, $pivotTableAlias, $localPivotKey, $currentTableAlias, $localKey) {
230+
$join->on($pivotTableAlias.'.'.$localPivotKey, '=', $currentTableAlias.'.'.$localKey);
231+
232+
$this->joinQuery($join, $relatedRelation, $pivotTableAlias);
233+
});
234+
235+
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $pivotTableAlias, $relatedPivotKey) {
236+
$join->on($relatedTableAlias.'.'.$relatedKey, '=', $pivotTableAlias.'.'.$relatedPivotKey);
237+
215238
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
216239
});
217240
} else {
218241
throw new InvalidRelation();
219242
}
220243
}
221244

245+
if ('pivot' === $nextRelation) {
246+
$relatedTableAlias = $pivotTableAlias;
247+
++$i;
248+
}
249+
222250
$currentModel = $relatedModel;
223251
$currentTableAlias = $relatedTableAlias;
224252

‎src/Exceptions/InvalidRelationClause.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
class InvalidRelationClause extends \Exception
66
{
7-
public $message = 'Package allows only following clauses on relation : where, orWhere, withTrashed, onlyTrashed and withoutTrashed.';
7+
public $message = 'Package allows only following clauses on relation : where, orWhere, whereRaw, orderByRaw, withTrashed, onlyTrashed and withoutTrashed.';
88
}

‎src/Relations/BelongsToManyJoin.php

+11
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\BelongsToMany;
7+
8+
class BelongsToManyJoin extends BelongsToMany
9+
{
10+
use JoinRelationTrait;
11+
}

‎src/Traits/ExtendRelationsTrait.php

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Fico7489\Laravel\EloquentJoin\Traits;
44

55
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
6+
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToManyJoin;
67
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
78
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
89
use Illuminate\Database\Eloquent\Builder;
@@ -15,6 +16,12 @@ protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $owne
1516
return new BelongsToJoin($query, $child, $foreignKey, $ownerKey, $relation);
1617
}
1718

19+
protected function newBelongsToMany(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey,
20+
$parentKey, $relatedKey, $relationName = null)
21+
{
22+
return new BelongsToManyJoin($query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName);
23+
}
24+
1825
protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey)
1926
{
2027
return new HasOneJoin($query, $parent, $foreignKey, $localKey);

‎tests/Models/City.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function zipCodePrimary()
2525

2626
public function sellers()
2727
{
28-
return $this->belongsToMany(Seller::class, 'locations', 'seller_id', 'city_id');
28+
return $this->belongsToMany(Seller::class, 'locations', 'city_id', 'seller_id');
2929
}
3030

3131
public function zipCodes()

‎tests/Models/Seller.php

+5
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,9 @@ public function city()
6363
{
6464
return $this->belongsTo(City::class);
6565
}
66+
67+
public function tags()
68+
{
69+
return $this->morphToMany(Tag::class, 'taggable');
70+
}
6671
}

‎tests/Models/Tag.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
4+
5+
use Illuminate\Database\Eloquent\SoftDeletes;
6+
7+
class Tag extends BaseModel
8+
{
9+
use SoftDeletes;
10+
11+
protected $table = 'tags';
12+
13+
protected $fillable = ['name'];
14+
15+
public function sellers()
16+
{
17+
return $this->morphedByMany(Seller::class, 'taggable');
18+
}
19+
20+
public function users()
21+
{
22+
return $this->morphedByMany(User::class, 'taggable');
23+
}
24+
}

‎tests/Models/User.php

+5
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@ class User extends BaseModel
1111
protected $table = 'users';
1212

1313
protected $fillable = ['name'];
14+
15+
public function tags()
16+
{
17+
return $this->morphToMany(Tag::class, 'taggable');
18+
}
1419
}

‎tests/TestCase.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,6 @@ protected function assertQueryMatches($expected, $actual)
120120
$expected = str_replace(['"'], '`', $expected);
121121
}
122122

123-
$this->assertRegExp($expected, $actual);
123+
$this->assertMatchesRegularExpression($expected, $actual);
124124
}
125125
}

‎tests/Tests/ExceptionTest.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationClause;
99
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationGlobalScope;
1010
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationWhere;
11-
use Fico7489\Laravel\EloquentJoin\Tests\Models\City;
1211
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
1312
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
1413

@@ -17,7 +16,7 @@ class ExceptionTest extends TestCase
1716
public function testInvalidRelation()
1817
{
1918
try {
20-
City::whereJoin('sellers.id', '=', 'test')->get();
19+
Seller::whereJoin('tags.name', '=', 'test')->get();
2120
} catch (InvalidRelation $e) {
2221
$this->assertEquals((new InvalidRelation())->message, $e->getMessage());
2322

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
4+
5+
use Fico7489\Laravel\EloquentJoin\Tests\Models\City;
6+
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
7+
8+
class BelongToManyTest extends TestCase
9+
{
10+
public function testBelongsToMany()
11+
{
12+
City::joinRelations('sellers')->get();
13+
14+
$queryTest = 'select cities.* from "cities"
15+
left join "locations" on "locations"."city_id" = "cities"."id"
16+
left join "sellers" on "sellers"."id" = "locations"."seller_id"
17+
where "cities"."deleted_at" is null
18+
group by "cities"."id"';
19+
20+
$this->assertQueryMatches($queryTest, $this->fetchQuery());
21+
}
22+
}

‎tests/Tests/Relations/HasManyTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
44

55
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
6+
use Fico7489\Laravel\EloquentJoin\Tests\Models\State;
67
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
78

89
class HasManyTest extends TestCase
@@ -48,4 +49,18 @@ public function testHasManyBelongsTo()
4849

4950
$this->assertQueryMatches($queryTest, $this->fetchQuery());
5051
}
52+
53+
public function testHasManyBelongsToMany()
54+
{
55+
State::joinRelations('cities.sellers')->get();
56+
57+
$queryTest = 'select states.* from "states"
58+
left join "cities" on "cities"."state_id" = "states"."id" and "cities"."deleted_at" is null
59+
left join "locations" on "locations"."city_id" = "cities"."id"
60+
left join "sellers" on "sellers"."id" = "locations"."seller_id"
61+
where "states"."deleted_at" is null
62+
group by "states"."id"';
63+
64+
$this->assertQueryMatches($queryTest, $this->fetchQuery());
65+
}
5166
}

‎tests/database/migrations/2017_11_04_163552_create_database.php

+13
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@ public function up()
153153
$table->unsignedInteger('id_seller_foreign')->nullable();
154154
$table->foreign('id_seller_foreign')->references('id')->on('sellers');
155155
});
156+
157+
Schema::create('tags', function (Blueprint $table) {
158+
$table->increments('id_location_primary');
159+
160+
$table->string('name');
161+
});
162+
163+
Schema::create('taggables', function (Blueprint $table) {
164+
$table->increments('tag_id');
165+
166+
$table->unsignedInteger('taggable_id');
167+
$table->string('taggable_type');
168+
});
156169
}
157170

158171
/**

0 commit comments

Comments
 (0)
Please sign in to comment.