Skip to content

Commit acfdb19

Browse files
ithuismedspec
authored andcommitted
requested code cleanup
1 parent 8eaad01 commit acfdb19

File tree

4 files changed

+225
-75
lines changed

4 files changed

+225
-75
lines changed

src/Relations/MorphToMany.php

Lines changed: 224 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,179 @@
44

55
namespace MongoDB\Laravel\Relations;
66

7+
use Arr;
78
use Illuminate\Database\Eloquent\Builder;
9+
use Illuminate\Database\Eloquent\Collection;
810
use Illuminate\Database\Eloquent\Model;
11+
use Illuminate\Database\Eloquent\Relations\MorphToMany as EloquentMorphToMany;
912

10-
class MorphToMany extends BelongsToMany
13+
use function array_diff;
14+
use function array_keys;
15+
use function array_map;
16+
use function array_merge;
17+
use function array_values;
18+
use function count;
19+
use function is_array;
20+
use function is_numeric;
21+
22+
class MorphToMany extends EloquentMorphToMany
1123
{
12-
protected $morphType;
24+
/**
25+
* Get the key for comparing against the parent key in "has" query.
26+
*
27+
* @return string
28+
*/
29+
public function getHasCompareKey()
30+
{
31+
return $this->getForeignKey();
32+
}
33+
34+
/** @inheritdoc */
35+
public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
36+
{
37+
return $query;
38+
}
1339

14-
protected $morphClass;
40+
/** @inheritdoc */
41+
protected function hydratePivotRelation(array $models)
42+
{
43+
// Do nothing.
44+
}
1545

1646
/**
17-
* Create a new morph to many relationship instance.
47+
* Set the select clause for the relation query.
1848
*
19-
* @param Builder $query
20-
* @param Model $parent
21-
* @param string $name
22-
* @param string $table
23-
* @param string $foreignPivotKey
24-
* @param string $relatedPivotKey
25-
* @param string $parentKey
26-
* @param string $relatedKey
27-
* @param string|null $relationName
28-
* @param bool $inverse
29-
*
30-
* @return void
49+
* @return array
3150
*/
32-
public function __construct(
33-
Builder $query,
34-
Model $parent,
35-
$name,
36-
$table,
37-
$foreignPivotKey,
38-
$relatedPivotKey,
39-
$parentKey,
40-
$relatedKey,
41-
$relationName = null,
42-
protected $inverse = false,
43-
) {
44-
$this->morphType = $name . '_type';
45-
$this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass();
46-
47-
parent::__construct(
48-
$query,
49-
$parent,
50-
$table,
51-
$foreignPivotKey,
52-
$relatedPivotKey,
53-
$parentKey,
54-
$relatedKey,
55-
$relationName,
56-
);
51+
protected function getSelectColumns(array $columns = ['*'])
52+
{
53+
return $columns;
54+
}
55+
56+
/** @inheritdoc */
57+
protected function shouldSelect(array $columns = ['*'])
58+
{
59+
return $columns;
60+
}
61+
62+
/** @inheritdoc */
63+
public function addConstraints()
64+
{
65+
if (static::$constraints) {
66+
$this->setWhere();
67+
}
5768
}
5869

5970
/**
60-
* Attach a model to the parent.
61-
*
62-
* @param mixed $id
63-
* @param array $attributes
64-
* @param bool $touch
71+
* Set the where clause for the relation query.
6572
*
66-
* @return void
73+
* @return $this
6774
*/
75+
protected function setWhere()
76+
{
77+
$foreign = $this->getForeignKey();
78+
79+
if ($this->getInverse()) {
80+
$this->query->where($foreign, '=', $this->parent->getKey());
81+
} else {
82+
$relatedModels = $this->parent->{$this->relatedPivotKey} ?? [];
83+
$this->query->whereIn($this->relatedKey, $relatedModels);
84+
}
85+
86+
return $this;
87+
}
88+
89+
/** @inheritdoc */
90+
public function save(Model $model, array $joining = [], $touch = true)
91+
{
92+
$model->save(['touch' => false]);
93+
94+
$this->attach($model, $joining, $touch);
95+
96+
return $model;
97+
}
98+
99+
/** @inheritdoc */
100+
public function create(array $attributes = [], array $joining = [], $touch = true)
101+
{
102+
$instance = $this->related->newInstance($attributes);
103+
104+
// Once we save the related model, we need to attach it to the base model via
105+
// through intermediate table so we'll use the existing "attach" method to
106+
// accomplish this which will insert the record and any more attributes.
107+
$instance->save(['touch' => false]);
108+
109+
$this->attach($instance, $joining, $touch);
110+
111+
return $instance;
112+
}
113+
114+
/** @inheritdoc */
115+
public function sync($ids, $detaching = true)
116+
{
117+
$changes = [
118+
'attached' => [],
119+
'detached' => [],
120+
'updated' => [],
121+
];
122+
123+
if ($ids instanceof Collection) {
124+
$ids = $ids->modelKeys();
125+
}
126+
127+
// First we need to attach any of the associated models that are not currently
128+
// in this joining table. We'll spin through the given IDs, checking to see
129+
// if they exist in the array of current ones, and if not we will insert.
130+
$current = $this->parent->{$this->relatedPivotKey} ?: [];
131+
132+
// See issue #256.
133+
if ($current instanceof Collection) {
134+
$current = $ids->modelKeys();
135+
}
136+
137+
$records = $this->formatSyncList($ids);
138+
139+
$current = Arr::wrap($current);
140+
141+
$detach = array_diff($current, array_keys($records));
142+
143+
// We need to make sure we pass a clean array, so that it is not interpreted
144+
// as an associative array.
145+
$detach = array_values($detach);
146+
147+
// Next, we will take the differences of the currents and given IDs and detach
148+
// all of the entities that exist in the "current" array but are not in the
149+
// the array of the IDs given to the method which will complete the sync.
150+
if ($detaching && count($detach) > 0) {
151+
$this->detach($detach);
152+
153+
$changes['detached'] = (array) array_map(function ($v) {
154+
return is_numeric($v) ? (int) $v : (string) $v;
155+
}, $detach);
156+
}
157+
158+
// Now we are finally ready to attach the new records. Note that we'll disable
159+
// touching until after the entire operation is complete so we don't fire a
160+
// ton of touch operations until we are totally done syncing the records.
161+
$changes = array_merge(
162+
$changes,
163+
$this->attachNew($records, $current, false),
164+
);
165+
166+
if (count($changes['attached']) || count($changes['updated'])) {
167+
$this->touchIfTouching();
168+
}
169+
170+
return $changes;
171+
}
172+
173+
/** @inheritdoc */
174+
public function updateExistingPivot($id, array $attributes, $touch = true)
175+
{
176+
// Do nothing, we have no pivot table.
177+
}
178+
179+
/** @inheritdoc */
68180
public function attach($id, array $attributes = [], $touch = true)
69181
{
70182
if ($id instanceof Model) {
@@ -137,53 +249,94 @@ public function detach($ids = [], $touch = true)
137249
return count($ids);
138250
}
139251

252+
/** @inheritdoc */
253+
protected function buildDictionary(Collection $results)
254+
{
255+
$foreign = $this->foreignPivotKey;
256+
257+
// First we will build a dictionary of child models keyed by the foreign key
258+
// of the relation so that we will easily and quickly match them to their
259+
// parents without having a possibly slow inner loops for every models.
260+
$dictionary = [];
261+
262+
foreach ($results as $result) {
263+
foreach ($result->$foreign as $item) {
264+
$dictionary[$item][] = $result;
265+
}
266+
}
267+
268+
return $dictionary;
269+
}
270+
271+
/** @inheritdoc */
272+
public function newPivotQuery()
273+
{
274+
return $this->newRelatedQuery();
275+
}
140276

141277
/**
142-
* Get the foreign key "type" name.
278+
* Create a new query builder for the related model.
143279
*
144-
* @return string
280+
* @return \Illuminate\Database\Query\Builder
145281
*/
146-
public function getMorphType()
282+
public function newRelatedQuery()
147283
{
148-
return $this->morphType;
284+
return $this->related->newQuery();
149285
}
150286

151287
/**
152-
* Get the class name of the parent model.
288+
* Get the fully qualified foreign key for the relation.
153289
*
154290
* @return string
155291
*/
156-
public function getMorphClass()
292+
public function getForeignKey()
157293
{
158-
return $this->morphClass;
294+
return $this->foreignPivotKey;
159295
}
160296

161-
/**
162-
* Get the indicator for a reverse relationship.
163-
*
164-
* @return bool
165-
*/
166-
public function getInverse()
297+
/** @inheritdoc */
298+
public function getQualifiedForeignPivotKeyName()
299+
{
300+
return $this->foreignPivotKey;
301+
}
302+
303+
/** @inheritdoc */
304+
public function getQualifiedRelatedPivotKeyName()
167305
{
168-
return $this->inverse;
306+
return $this->relatedPivotKey;
169307
}
170308

171309
/**
172-
* Set the where clause for the relation query.
310+
* Format the sync list so that it is keyed by ID. (Legacy Support)
311+
* The original function has been renamed to formatRecordsList since Laravel 5.3.
173312
*
174-
* @return $this
313+
* @deprecated
314+
*
315+
* @return array
175316
*/
176-
protected function setWhere()
317+
protected function formatSyncList(array $records)
177318
{
178-
$foreign = $this->getForeignKey();
319+
$results = [];
320+
foreach ($records as $id => $attributes) {
321+
if (! is_array($attributes)) {
322+
[$id, $attributes] = [$attributes, []];
323+
}
179324

180-
if ($this->getInverse()) {
181-
$this->query->where($foreign, '=', $this->parent->getKey());
182-
} else {
183-
$relatedModels = $this->parent->{$this->relatedPivotKey} ?? [];
184-
$this->query->whereIn($this->relatedKey, $relatedModels);
325+
$results[$id] = $attributes;
185326
}
186327

187-
return $this;
328+
return $results;
329+
}
330+
331+
/**
332+
* Get the name of the "where in" method for eager loading.
333+
*
334+
* @param string $key
335+
*
336+
* @return string
337+
*/
338+
protected function whereInMethod(Model $model, $key)
339+
{
340+
return 'whereIn';
188341
}
189342
}

tests/Models/Client.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Illuminate\Database\Eloquent\Relations\HasMany;
99
use Illuminate\Database\Eloquent\Relations\MorphOne;
1010
use MongoDB\Laravel\Eloquent\Model as Eloquent;
11-
// use Illuminate\Database\Eloquent\Relations\MorphToMany;
1211

1312
class Client extends Eloquent
1413
{

tests/Models/Label.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
namespace MongoDB\Laravel\Tests\Models;
66

77
use MongoDB\Laravel\Eloquent\Model as Eloquent;
8-
// use Illuminate\Database\Eloquent\Relations\MorphToMany;
9-
// use Illuminate\Database\Eloquent\Relations\MorphByMany;
108

119
/**
1210
* @property string $title

tests/RelationsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ public function testMorph(): void
402402
public function testMorphToMany(): void
403403
{
404404

405-
// cerate user
405+
// create user
406406
$user = User::updateOrCreate(['name' => 'John Doe']);
407407
// create client
408408
$client = Client::updateOrCreate(['name' => 'Jane Doe']);

0 commit comments

Comments
 (0)