From 0073de2a0aa5accf308e37dc233689cdb45a870f Mon Sep 17 00:00:00 2001 From: Alex Wass Date: Wed, 27 Nov 2024 23:42:46 +0000 Subject: [PATCH 1/3] Add the pivot's related model when creating from attributes --- src/Illuminate/Database/Eloquent/Model.php | 7 ++++--- .../Eloquent/Relations/Concerns/AsPivot.php | 20 ++++++++++++++++--- .../Concerns/InteractsWithPivotTable.php | 4 ++-- .../Eloquent/Relations/MorphToMany.php | 4 ++-- tests/Database/DatabaseEloquentPivotTest.php | 10 ++++++++++ 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index bca7e9160598..c1ecdd40005a 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1622,12 +1622,13 @@ protected function newBaseQueryBuilder() * @param string $table * @param bool $exists * @param string|null $using + * @param \Illuminate\Database\Eloquent\Model|null $related * @return \Illuminate\Database\Eloquent\Relations\Pivot */ - public function newPivot(self $parent, array $attributes, $table, $exists, $using = null) + public function newPivot(self $parent, array $attributes, $table, $exists, $using = null, ?self $related = null) { - return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists) - : Pivot::fromAttributes($parent, $attributes, $table, $exists); + return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists, $related) + : Pivot::fromAttributes($parent, $attributes, $table, $exists, $related); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php index ac2411f806c6..d6c62acd23de 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php @@ -14,6 +14,13 @@ trait AsPivot */ public $pivotParent; + /** + * The related model of the relationship. + * + * @var \Illuminate\Database\Eloquent\Model + */ + public $pivotRelated; + /** * The name of the foreign key column. * @@ -35,9 +42,10 @@ trait AsPivot * @param array $attributes * @param string $table * @param bool $exists + * @param \Illuminate\Database\Eloquent\Model|null $related * @return static */ - public static function fromAttributes(Model $parent, $attributes, $table, $exists = false) + public static function fromAttributes(Model $parent, $attributes, $table, $exists = false, ?Model $related = null) { $instance = new static; @@ -56,6 +64,11 @@ public static function fromAttributes(Model $parent, $attributes, $table, $exist // from the developer's point of view. We can use the parents to get these. $instance->pivotParent = $parent; + // Also store a model instance of the relationship that was called on the parent + // so the developer is able to identify which relationship methods were used + // in their custom pivot class, and within their fromRawAttributes method. + $instance->pivotRelated = $related; + $instance->exists = $exists; return $instance; @@ -68,11 +81,12 @@ public static function fromAttributes(Model $parent, $attributes, $table, $exist * @param array $attributes * @param string $table * @param bool $exists + * @param \Illuminate\Database\Eloquent\Model|null $related * @return static */ - public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false) + public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false, ?Model $related = null) { - $instance = static::fromAttributes($parent, [], $table, $exists); + $instance = static::fromAttributes($parent, [], $table, $exists, $related); $instance->timestamps = $instance->hasTimestampAttributes($attributes); diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index b249858a65be..401bb04f1b2b 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -500,7 +500,7 @@ protected function getCurrentlyAttachedPivots() return $this->newPivotQuery()->get()->map(function ($record) { $class = $this->using ?: Pivot::class; - $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true); + $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true, $this->related); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); }); @@ -518,7 +518,7 @@ public function newPivot(array $attributes = [], $exists = false) $attributes = array_merge(array_column($this->pivotValues, 'value', 'column'), $attributes); $pivot = $this->related->newPivot( - $this->parent, $attributes, $this->table, $exists, $this->using + $this->parent, $attributes, $this->table, $exists, $this->using, $this->related ); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 9f9b46e51b95..784bf8cdddf5 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -156,8 +156,8 @@ public function newPivot(array $attributes = [], $exists = false) $attributes = array_merge([$this->morphType => $this->morphClass], $attributes); - $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) - : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); + $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists, $this->related) + : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists, $this->related); $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) ->setMorphType($this->morphType) diff --git a/tests/Database/DatabaseEloquentPivotTest.php b/tests/Database/DatabaseEloquentPivotTest.php index ad774d7c1a68..162028ebd11b 100755 --- a/tests/Database/DatabaseEloquentPivotTest.php +++ b/tests/Database/DatabaseEloquentPivotTest.php @@ -35,6 +35,16 @@ public function testPropertiesAreSetCorrectly() $this->assertSame('connection', $pivot->getConnectionName()); $this->assertSame('table', $pivot->getTable()); $this->assertTrue($pivot->exists); + $this->assertSame($parent, $pivot->pivotParent); + } + + public function testRelatedPivotModelCanBeSetCorrectly() + { + $parent = new DummyModel; + $related = new DummyModel; + $pivot = Pivot::fromAttributes($parent, ['foo' => 'bar', 'created_at' => '2024-11-27'], 'table', true, $related); + + $this->assertSame($related, $pivot->pivotRelated); } public function testMutatorsAreCalledFromConstructor() From b2c1b4325cab56e54646896c3caa9d54000197a7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 2 Dec 2024 08:16:07 -0800 Subject: [PATCH 2/3] formatting --- src/Illuminate/Database/Eloquent/Model.php | 7 +++-- .../Eloquent/Relations/Concerns/AsPivot.php | 27 ++++++++++++------- .../Concerns/InteractsWithPivotTable.php | 7 ++--- .../Eloquent/Relations/MorphToMany.php | 5 ++-- tests/Database/DatabaseEloquentPivotTest.php | 9 ------- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index c1ecdd40005a..bca7e9160598 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1622,13 +1622,12 @@ protected function newBaseQueryBuilder() * @param string $table * @param bool $exists * @param string|null $using - * @param \Illuminate\Database\Eloquent\Model|null $related * @return \Illuminate\Database\Eloquent\Relations\Pivot */ - public function newPivot(self $parent, array $attributes, $table, $exists, $using = null, ?self $related = null) + public function newPivot(self $parent, array $attributes, $table, $exists, $using = null) { - return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists, $related) - : Pivot::fromAttributes($parent, $attributes, $table, $exists, $related); + return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists) + : Pivot::fromAttributes($parent, $attributes, $table, $exists); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php index d6c62acd23de..afd328a7ea94 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php @@ -42,10 +42,9 @@ trait AsPivot * @param array $attributes * @param string $table * @param bool $exists - * @param \Illuminate\Database\Eloquent\Model|null $related * @return static */ - public static function fromAttributes(Model $parent, $attributes, $table, $exists = false, ?Model $related = null) + public static function fromAttributes(Model $parent, $attributes, $table, $exists = false) { $instance = new static; @@ -64,11 +63,6 @@ public static function fromAttributes(Model $parent, $attributes, $table, $exist // from the developer's point of view. We can use the parents to get these. $instance->pivotParent = $parent; - // Also store a model instance of the relationship that was called on the parent - // so the developer is able to identify which relationship methods were used - // in their custom pivot class, and within their fromRawAttributes method. - $instance->pivotRelated = $related; - $instance->exists = $exists; return $instance; @@ -81,12 +75,11 @@ public static function fromAttributes(Model $parent, $attributes, $table, $exist * @param array $attributes * @param string $table * @param bool $exists - * @param \Illuminate\Database\Eloquent\Model|null $related * @return static */ - public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false, ?Model $related = null) + public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false) { - $instance = static::fromAttributes($parent, [], $table, $exists, $related); + $instance = static::fromAttributes($parent, [], $table, $exists); $instance->timestamps = $instance->hasTimestampAttributes($attributes); @@ -228,6 +221,19 @@ public function setPivotKeys($foreignKey, $relatedKey) return $this; } + /** + * Set the related model of the relationship. + * + * @param \Illuminate\Database\Eloquent\Model|null $related + * @return $this + */ + public function setRelatedModel(?Model $related = null) + { + $this->pivotRelated = $related; + + return $this; + } + /** * Determine if the pivot model or given attributes has timestamp attributes. * @@ -340,6 +346,7 @@ protected function newQueryForCollectionRestoration(array $ids) public function unsetRelations() { $this->pivotParent = null; + $this->pivotRelated = null; $this->relations = []; return $this; diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 401bb04f1b2b..87af10f28e9f 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -500,7 +500,8 @@ protected function getCurrentlyAttachedPivots() return $this->newPivotQuery()->get()->map(function ($record) { $class = $this->using ?: Pivot::class; - $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true, $this->related); + $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true) + ->setRelatedModel($this->related); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); }); @@ -518,8 +519,8 @@ public function newPivot(array $attributes = [], $exists = false) $attributes = array_merge(array_column($this->pivotValues, 'value', 'column'), $attributes); $pivot = $this->related->newPivot( - $this->parent, $attributes, $this->table, $exists, $this->using, $this->related - ); + $this->parent, $attributes, $this->table, $exists, $this->using + )->setRelatedModel($this->related); return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 784bf8cdddf5..86e51d2af159 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -156,10 +156,11 @@ public function newPivot(array $attributes = [], $exists = false) $attributes = array_merge([$this->morphType => $this->morphClass], $attributes); - $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists, $this->related) - : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists, $this->related); + $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists) + : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) + ->setRelatedModel($this->related) ->setMorphType($this->morphType) ->setMorphClass($this->morphClass); diff --git a/tests/Database/DatabaseEloquentPivotTest.php b/tests/Database/DatabaseEloquentPivotTest.php index 162028ebd11b..704a917f7b52 100755 --- a/tests/Database/DatabaseEloquentPivotTest.php +++ b/tests/Database/DatabaseEloquentPivotTest.php @@ -38,15 +38,6 @@ public function testPropertiesAreSetCorrectly() $this->assertSame($parent, $pivot->pivotParent); } - public function testRelatedPivotModelCanBeSetCorrectly() - { - $parent = new DummyModel; - $related = new DummyModel; - $pivot = Pivot::fromAttributes($parent, ['foo' => 'bar', 'created_at' => '2024-11-27'], 'table', true, $related); - - $this->assertSame($related, $pivot->pivotRelated); - } - public function testMutatorsAreCalledFromConstructor() { $parent = m::mock(Model::class.'[getConnectionName]'); From 44643be9c0fb1c4a04c9470949bc9d354e3482ba Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 2 Dec 2024 08:18:14 -0800 Subject: [PATCH 3/3] formatting --- .../Relations/Concerns/InteractsWithPivotTable.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 87af10f28e9f..18a2501b66ef 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -500,10 +500,11 @@ protected function getCurrentlyAttachedPivots() return $this->newPivotQuery()->get()->map(function ($record) { $class = $this->using ?: Pivot::class; - $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true) - ->setRelatedModel($this->related); + $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true); - return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); + return $pivot + ->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) + ->setRelatedModel($this->related); }); } @@ -520,9 +521,11 @@ public function newPivot(array $attributes = [], $exists = false) $pivot = $this->related->newPivot( $this->parent, $attributes, $this->table, $exists, $this->using - )->setRelatedModel($this->related); + ); - return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey); + return $pivot + ->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) + ->setRelatedModel($this->related); } /**