From 4d312f8c8497bb03ef4440eec9eea8261d414dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Tue, 6 Oct 2020 18:30:11 +0200 Subject: [PATCH 01/48] Added SortableRelation trait --- src/Database/Traits/SortableRelation.php | 117 +++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/Database/Traits/SortableRelation.php diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php new file mode 100644 index 000000000..de5207729 --- /dev/null +++ b/src/Database/Traits/SortableRelation.php @@ -0,0 +1,117 @@ + 'sort_order_column']; + * + * To set orders: + * + * $model->setSortableRelationOrder($relationName, $recordIds, $recordOrders); + * + */ +trait SortableRelation +{ + /** + * @var array The array of all sortable relations with their sort_order pivot column. + * + * public $sortableRelations = ['related_model' => 'sort_order']; + */ + + /** + * Boot the SortableRelation trait for this model. + * Make sure to add the sort_order value if a related model has been attached. + * @return void + */ + public function initializeSortableRelation() + { + $this->bindEvent('model.relation.afterAttach', function($relationName, $attached, $data) { + if (array_key_exists($relationName, $this->getSortableRelations())) { + $column = $this->getRelationSortOrderColumn($relationName); + + $order = $this->$relationName()->max($column); + + foreach ($attached as $id) { + $order++; + $this->$relationName()->updateExistingPivot($id, [$column => $order]); + } + } + }); + + // Make sure all defined sortable relations load the sort_order column as pivot data. + foreach ($this->getSortableRelations() as $relationName => $column) { + $definition = $this->getRelationDefinition($relationName); + $pivot = array_wrap(array_get($definition, 'pivot', [])); + + if (!in_array($column, $pivot)) { + $pivot[] = $column; + $definition['pivot'] = $pivot; + + $relationType = $this->getRelationType($relationName); + $this->$relationType[$relationName] = $definition; + } + } + } + + /** + * Sets the sort order of records to the specified orders. If the orders is + * undefined, the record identifier is used. + * @param string $relation + * @param mixed $itemIds + * @param array $itemOrders + * @return void + */ + public function setRelationOrder($relationName, $itemIds, $itemOrders = null) + { + if (!is_array($itemIds)) { + $itemIds = [$itemIds]; + } + + if ($itemOrders === null) { + $itemOrders = $itemIds; + } + + if (count($itemIds) != count($itemOrders)) { + throw new Exception('Invalid setRelationOrder call - count of itemIds do not match count of itemOrders'); + } + + foreach ($itemIds as $index => $id) { + $order = $itemOrders[$index]; + + $this->$relationName()->updateExistingPivot($id, [ + $this->getRelationSortOrderColumn($relationName) => (int)$order + ]); + } + } + + /** + * Get the name of the "sort_order" column. + * @param string $relation + * @return string + */ + public function getRelationSortOrderColumn($relation) + { + return $this->getSortableRelations()[$relation] ?? 'sort_order'; + } + + /** + * Returns all configured sortable relations. + * @return array + */ + protected function getSortableRelations() + { + if (property_exists($this, 'sortableRelations')) { + return $this->sortableRelations; + } + return []; + } +} From 557b6109dde35e23df0115bf6046f4e19249b0db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Tue, 6 Oct 2020 18:43:31 +0200 Subject: [PATCH 02/48] Added space after function keyword --- src/Database/Traits/SortableRelation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index de5207729..ae03f6a88 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -34,7 +34,7 @@ trait SortableRelation */ public function initializeSortableRelation() { - $this->bindEvent('model.relation.afterAttach', function($relationName, $attached, $data) { + $this->bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) { if (array_key_exists($relationName, $this->getSortableRelations())) { $column = $this->getRelationSortOrderColumn($relationName); From 2d1f3f430c231181ba8907a09071cffab8ff4b60 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 27 Oct 2020 10:34:02 -0400 Subject: [PATCH 03/48] add before/after save & create events --- src/Database/Relations/HasOneOrMany.php | 60 ++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/Database/Relations/HasOneOrMany.php b/src/Database/Relations/HasOneOrMany.php index 7d2325257..d06ed5ade 100644 --- a/src/Database/Relations/HasOneOrMany.php +++ b/src/Database/Relations/HasOneOrMany.php @@ -16,12 +16,42 @@ trait HasOneOrMany */ public function save(Model $model, $sessionKey = null) { + /** + * @event model.relation.beforeSave + * Called before saving a relation (only for HasOneOrMany relation) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeSave', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeSave', [$this->relationName, $this->related], true) === false) { + return; + } + if ($sessionKey === null) { return parent::save($model); } $this->add($model, $sessionKey); - return $model->save() ? $model : false; + $result = $model->save() ? $model : false; + + /** + * @event model.relation.afterSave + * Called after saving a relation (only for HasOneOrMany relation) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterSave', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterSave', [$this->relationName, $this->related]); + + return $result; } /** @@ -41,12 +71,40 @@ public function saveMany($models, $sessionKey = null) */ public function create(array $attributes = [], $sessionKey = null) { + /** + * @event model.relation.beforeCreate + * Called before creating a new relation between models (only for HasOneOrMany relation) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeCreate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeCreate', [$this->relationName, $this->related], true) === false) { + return; + } + $model = parent::create($attributes); if ($sessionKey !== null) { $this->add($model, $sessionKey); } + /** + * @event model.relation.afterCreate + * Called after creating a new relation between models (only for HasOneOrMany relation) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterCreate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterCreate', [$this->relationName, $this->related]); + return $model; } From da8579d4e0b57abca790188b036eda5eff50e3a8 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 27 Oct 2020 14:46:58 -0400 Subject: [PATCH 04/48] add before/after associate/dissociate events --- src/Database/Relations/BelongsTo.php | 56 +++++++++++++++++++ src/Database/Relations/MorphTo.php | 81 ++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index afd3403a5..7be22acf2 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -28,12 +28,40 @@ public function __construct(Builder $query, Model $child, $foreignKey, $ownerKey */ public function add(Model $model, $sessionKey = null) { + /** + * @event model.relation.beforeAssociate + * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true) === false) { + return; + } + if ($sessionKey === null) { $this->associate($model); } else { $this->child->bindDeferred($this->relationName, $model, $sessionKey); } + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); } /** @@ -41,12 +69,40 @@ public function add(Model $model, $sessionKey = null) */ public function remove(Model $model, $sessionKey = null) { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true) === false) { + return; + } + if ($sessionKey === null) { $this->dissociate(); } else { $this->child->unbindDeferred($this->relationName, $model, $sessionKey); } + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); } /** diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index 39975e0c8..a882cf212 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -70,4 +70,85 @@ public function getSimpleValue() $this->parent->getAttribute($this->morphType) ]; } + + /** + * Associate the model instance to the given parent. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @return \Illuminate\Database\Eloquent\Model + */ + public function associate($model) + { + /** + * @event model.relation.beforeAssociate + * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true) === false) { + return; + } + + $result = parent::associate($model); + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + + return $result; + } + + /** + * Dissociate previously dissociated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() + { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + if ($this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true) === false) { + return; + } + + $result = parent::dissociate(); + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + + return $result; + } } From 73ac6f0ea4ed7f9d4e337bb6687dcd124e864b5d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 27 Oct 2020 15:28:30 -0400 Subject: [PATCH 05/48] Revert "add before/after save & create events" This reverts commit 2d1f3f430c231181ba8907a09071cffab8ff4b60. --- src/Database/Relations/HasOneOrMany.php | 60 +------------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/src/Database/Relations/HasOneOrMany.php b/src/Database/Relations/HasOneOrMany.php index d06ed5ade..7d2325257 100644 --- a/src/Database/Relations/HasOneOrMany.php +++ b/src/Database/Relations/HasOneOrMany.php @@ -16,42 +16,12 @@ trait HasOneOrMany */ public function save(Model $model, $sessionKey = null) { - /** - * @event model.relation.beforeSave - * Called before saving a relation (only for HasOneOrMany relation) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeSave', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - if ($this->parent->fireEvent('model.relation.beforeSave', [$this->relationName, $this->related], true) === false) { - return; - } - if ($sessionKey === null) { return parent::save($model); } $this->add($model, $sessionKey); - $result = $model->save() ? $model : false; - - /** - * @event model.relation.afterSave - * Called after saving a relation (only for HasOneOrMany relation) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterSave', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterSave', [$this->relationName, $this->related]); - - return $result; + return $model->save() ? $model : false; } /** @@ -71,40 +41,12 @@ public function saveMany($models, $sessionKey = null) */ public function create(array $attributes = [], $sessionKey = null) { - /** - * @event model.relation.beforeCreate - * Called before creating a new relation between models (only for HasOneOrMany relation) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeCreate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - if ($this->parent->fireEvent('model.relation.beforeCreate', [$this->relationName, $this->related], true) === false) { - return; - } - $model = parent::create($attributes); if ($sessionKey !== null) { $this->add($model, $sessionKey); } - /** - * @event model.relation.afterCreate - * Called after creating a new relation between models (only for HasOneOrMany relation) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterCreate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterCreate', [$this->relationName, $this->related]); - return $model; } From 766ac611d068f50069a4e3033992a037142e80c6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 27 Oct 2020 22:01:35 -0400 Subject: [PATCH 06/48] do not make halting events --- src/Database/Relations/BelongsTo.php | 8 ++------ src/Database/Relations/MorphTo.php | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index 7be22acf2..89d774a3f 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -39,9 +39,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - if ($this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); if ($sessionKey === null) { $this->associate($model); @@ -80,9 +78,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - if ($this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true); if ($sessionKey === null) { $this->dissociate(); diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index a882cf212..1ca0b955a 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -90,9 +90,7 @@ public function associate($model) * }); * */ - if ($this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true); $result = parent::associate($model); @@ -130,9 +128,7 @@ public function dissociate() * }); * */ - if ($this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); $result = parent::dissociate(); From 8052d989aedbd0a437a5d361a0151abf0edfffd2 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 30 Oct 2020 08:01:21 -0400 Subject: [PATCH 07/48] should not be halting events --- src/Database/Relations/BelongsToMany.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 0275ff3e2..cd818e97d 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -126,9 +126,7 @@ public function attach($id, array $attributes = [], $touch = true) * }); * */ - if ($this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData]); // Here we will insert the attachment records into the pivot table. Once we have // inserted the records, we will touch the relationships if necessary and the @@ -181,9 +179,7 @@ public function detach($ids = null, $touch = true) * }); * */ - if ($this->parent->fireEvent('model.relation.beforeDetach', [$this->relationName, $attachedIdList], true) === false) { - return; - } + $this->parent->fireEvent('model.relation.beforeDetach', [$this->relationName, $attachedIdList]); /* * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable From 7f42aff81442e532e27cf0074ffa57a23721c593 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 31 Oct 2020 00:15:28 -0400 Subject: [PATCH 08/48] return parent results for overriden parent methods --- src/Database/Relations/BelongsToMany.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index cd818e97d..fb6ba0330 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -103,9 +103,11 @@ public function create(array $attributes = [], array $pivotData = [], $sessionKe /** * Override attach() method of BelongToMany relation. * This is necessary in order to fire 'model.relation.beforeAttach', 'model.relation.afterAttach' events + * * @param mixed $id * @param array $attributes * @param bool $touch + * @return void */ public function attach($id, array $attributes = [], $touch = true) { @@ -154,9 +156,10 @@ public function attach($id, array $attributes = [], $touch = true) /** * Override detach() method of BelongToMany relation. * This is necessary in order to fire 'model.relation.beforeDetach', 'model.relation.afterDetach' events + * * @param null $ids * @param bool $touch - * @return int|void + * @return int */ public function detach($ids = null, $touch = true) { @@ -184,7 +187,7 @@ public function detach($ids = null, $touch = true) /* * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable */ - parent::detach($ids, $touch); + $result = parent::detach($ids, $touch); /** * @event model.relation.afterDetach @@ -198,6 +201,8 @@ public function detach($ids = null, $touch = true) * */ $this->parent->fireEvent('model.relation.afterDetach', [$this->relationName, $attachedIdList]); + + return $result; } /** From 5762c7e75d6b5df81a74f668e89608c5f7ab65a4 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 1 Nov 2020 08:58:34 -0500 Subject: [PATCH 09/48] override associate/dissociate and fire before/after events there --- src/Database/Relations/BelongsTo.php | 51 +++++++++++++++++++++------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index 89d774a3f..5acf33d24 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -27,6 +27,22 @@ public function __construct(Builder $query, Model $child, $foreignKey, $ownerKey * Adds a model to this relationship type. */ public function add(Model $model, $sessionKey = null) + { + if ($sessionKey === null) { + $this->associate($model); + } + else { + $this->child->bindDeferred($this->relationName, $model, $sessionKey); + } + } + + /** + * Associate the model instance to the given parent. + * + * @param \Illuminate\Database\Eloquent\Model|int|string $model + * @return \Illuminate\Database\Eloquent\Model + */ + public function associate($model) { /** * @event model.relation.beforeAssociate @@ -41,12 +57,7 @@ public function add(Model $model, $sessionKey = null) */ $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); - if ($sessionKey === null) { - $this->associate($model); - } - else { - $this->child->bindDeferred($this->relationName, $model, $sessionKey); - } + $result = parent::associate($model); /** * @event model.relation.afterAssociate @@ -60,12 +71,29 @@ public function add(Model $model, $sessionKey = null) * */ $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + + return $result; } /** * Removes a model from this relationship type. */ public function remove(Model $model, $sessionKey = null) + { + if ($sessionKey === null) { + $this->dissociate(); + } + else { + $this->child->unbindDeferred($this->relationName, $model, $sessionKey); + } + } + + /** + * Dissociate previously associated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() { /** * @event model.relation.beforeDissociate @@ -78,14 +106,9 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related], true); + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); - if ($sessionKey === null) { - $this->dissociate(); - } - else { - $this->child->unbindDeferred($this->relationName, $model, $sessionKey); - } + $result = parent::dissociate(); /** * @event model.relation.afterDissociate @@ -99,6 +122,8 @@ public function remove(Model $model, $sessionKey = null) * */ $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + + return $result; } /** From 93176f3fa1f9c891e5800c8948261be0f42250df Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 1 Nov 2020 09:01:38 -0500 Subject: [PATCH 10/48] do not pass true to Event::fire --- src/Database/Relations/MorphTo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index 1ca0b955a..1060913a5 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -90,7 +90,7 @@ public function associate($model) * }); * */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related], true); + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); $result = parent::associate($model); From b33c08b6ac5e36d046758a953139e37953707b2d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 1 Nov 2020 11:12:13 -0500 Subject: [PATCH 11/48] use a trait to avoid code duplication --- src/Database/Relations/BelongsOrMorphTo.php | 83 +++++++++++++++++++++ src/Database/Relations/BelongsTo.php | 78 +------------------ src/Database/Relations/MorphTo.php | 78 +------------------ 3 files changed, 85 insertions(+), 154 deletions(-) create mode 100644 src/Database/Relations/BelongsOrMorphTo.php diff --git a/src/Database/Relations/BelongsOrMorphTo.php b/src/Database/Relations/BelongsOrMorphTo.php new file mode 100644 index 000000000..e1891d77a --- /dev/null +++ b/src/Database/Relations/BelongsOrMorphTo.php @@ -0,0 +1,83 @@ +bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); + + $result = parent::associate($model); + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + + return $result; + } + + /** + * Dissociate previously dissociated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() + { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); + + $result = parent::dissociate(); + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * TODO: add example code + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + + return $result; + } +} diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index 5acf33d24..da5373b38 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -8,6 +8,7 @@ class BelongsTo extends BelongsToBase { use DeferOneOrMany; use DefinedConstraints; + use BelongsOrMorphTo; /** * @var string The "name" of the relationship. @@ -36,45 +37,6 @@ public function add(Model $model, $sessionKey = null) } } - /** - * Associate the model instance to the given parent. - * - * @param \Illuminate\Database\Eloquent\Model|int|string $model - * @return \Illuminate\Database\Eloquent\Model - */ - public function associate($model) - { - /** - * @event model.relation.beforeAssociate - * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); - - $result = parent::associate($model); - - /** - * @event model.relation.afterAssociate - * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); - - return $result; - } - /** * Removes a model from this relationship type. */ @@ -88,44 +50,6 @@ public function remove(Model $model, $sessionKey = null) } } - /** - * Dissociate previously associated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function dissociate() - { - /** - * @event model.relation.beforeDissociate - * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); - - $result = parent::dissociate(); - - /** - * @event model.relation.afterDissociate - * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); - - return $result; - } - /** * Helper for setting this relationship using various expected * values. For example, $model->relation = $value; diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index 1060913a5..dd7ec8ec0 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -7,6 +7,7 @@ class MorphTo extends MorphToBase { use DefinedConstraints; + use BelongsOrMorphTo; /** * @var string The "name" of the relationship. @@ -70,81 +71,4 @@ public function getSimpleValue() $this->parent->getAttribute($this->morphType) ]; } - - /** - * Associate the model instance to the given parent. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @return \Illuminate\Database\Eloquent\Model - */ - public function associate($model) - { - /** - * @event model.relation.beforeAssociate - * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); - - $result = parent::associate($model); - - /** - * @event model.relation.afterAssociate - * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); - - return $result; - } - - /** - * Dissociate previously dissociated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function dissociate() - { - /** - * @event model.relation.beforeDissociate - * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); - - $result = parent::dissociate(); - - /** - * @event model.relation.afterDissociate - * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code - * }); - * - */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); - - return $result; - } } From b59cf6156e045a7936485f436b434df88107cec9 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 1 Nov 2020 11:15:08 -0500 Subject: [PATCH 12/48] remove unused class --- src/Database/Relations/BelongsOrMorphTo.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Database/Relations/BelongsOrMorphTo.php b/src/Database/Relations/BelongsOrMorphTo.php index e1891d77a..ed9c3483c 100644 --- a/src/Database/Relations/BelongsOrMorphTo.php +++ b/src/Database/Relations/BelongsOrMorphTo.php @@ -1,7 +1,5 @@ Date: Sun, 1 Nov 2020 11:31:41 -0500 Subject: [PATCH 13/48] add example code in docblocks --- src/Database/Relations/BelongsOrMorphTo.php | 14 ++++++++++---- src/Database/Relations/BelongsToMany.php | 1 - 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Database/Relations/BelongsOrMorphTo.php b/src/Database/Relations/BelongsOrMorphTo.php index ed9c3483c..d5ddde8c5 100644 --- a/src/Database/Relations/BelongsOrMorphTo.php +++ b/src/Database/Relations/BelongsOrMorphTo.php @@ -17,7 +17,9 @@ public function associate($model) * Example usage: * * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } * }); * */ @@ -32,7 +34,8 @@ public function associate($model) * Example usage: * * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code + * $relatedClass = get_class($relatedModel); + * traceLog("Relation {$relationName} was associated to model {$relatedClass}."); * }); * */ @@ -55,7 +58,9 @@ public function dissociate() * Example usage: * * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } * }); * */ @@ -70,7 +75,8 @@ public function dissociate() * Example usage: * * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * TODO: add example code + * $relatedClass = get_class($relatedModel); + * traceLog("Relation {$relationName} was dissociated from model {$relatedClass}."); * }); * */ diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index fb6ba0330..744a3ea7a 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -123,7 +123,6 @@ public function attach($id, array $attributes = [], $touch = true) * $model->bindEvent('model.relation.beforeAttach', function (string $relationName, array $attachedIdList, array $insertData) use (\October\Rain\Database\Model $model) { * if (!$model->isRelationValid($attachedIdList)) { * throw new \Exception("Invalid relation!"); - * return false; * } * }); * From 7e2b6e4ca0d0edb0f527be4cc245aa94b572cfc6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 1 Nov 2020 17:34:42 -0500 Subject: [PATCH 14/48] add parent::detach results to event params --- src/Database/Relations/BelongsToMany.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 744a3ea7a..d76cd9281 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -194,12 +194,12 @@ public function detach($ids = null, $touch = true) * * Example usage: * - * $model->bindEvent('model.relation.afterDetach', function (string $relationName, array $attachedIdList) use (\October\Rain\Database\Model $model) { - * traceLog("Relation {$relationName} was removed", $attachedIdList); + * $model->bindEvent('model.relation.afterDetach', function (string $relationName, array $attachedIdList, int $result) use (\October\Rain\Database\Model $model) { + * traceLog("{$result} entries were detached for Relation {$relationName}"); * }); * */ - $this->parent->fireEvent('model.relation.afterDetach', [$this->relationName, $attachedIdList]); + $this->parent->fireEvent('model.relation.afterDetach', [$this->relationName, $attachedIdList, $result]); return $result; } From 4b015d4162be839cd02a2d3780b6c1db0f7d52db Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 09:27:37 -0500 Subject: [PATCH 15/48] add {before,after}Add events to AttachOneOrMany --- src/Database/Relations/AttachOneOrMany.php | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index 7ab21a28b..cc3338b89 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -166,6 +166,21 @@ public function add(Model $model, $sessionKey = null) } if ($sessionKey === null) { + /** + * @event model.relation.beforeAdd + * Called before adding a relation to the model (only for AttachOne/AttachMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + // Delete siblings for single attachments if ($this instanceof AttachOne) { $this->delete(); @@ -185,6 +200,20 @@ public function add(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterAdd + * Called after adding a relation to the model (only for AttachOne/AttachMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * traceLog("Relation {$relationName} was added to model {$relatedClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); From 4538d8078e4bce3188c15e64ea587db17fe7c55d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 13:55:02 -0500 Subject: [PATCH 16/48] fix examples --- src/Database/Relations/AttachOneOrMany.php | 3 ++- src/Database/Relations/BelongsOrMorphTo.php | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index cc3338b89..f26a67391 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -209,7 +209,8 @@ public function add(Model $model, $sessionKey = null) * * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { * $relatedClass = get_class($relatedModel); - * traceLog("Relation {$relationName} was added to model {$relatedClass}."); + * $modelClass = get_class($relatedModel); + * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); * }); * */ diff --git a/src/Database/Relations/BelongsOrMorphTo.php b/src/Database/Relations/BelongsOrMorphTo.php index d5ddde8c5..27c07c256 100644 --- a/src/Database/Relations/BelongsOrMorphTo.php +++ b/src/Database/Relations/BelongsOrMorphTo.php @@ -35,7 +35,8 @@ public function associate($model) * * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { * $relatedClass = get_class($relatedModel); - * traceLog("Relation {$relationName} was associated to model {$relatedClass}."); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); * }); * */ @@ -76,7 +77,8 @@ public function dissociate() * * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { * $relatedClass = get_class($relatedModel); - * traceLog("Relation {$relationName} was dissociated from model {$relatedClass}."); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was dissociated from {$modelClass}."); * }); * */ From 40215d0368aec32815c8300bc80e91250c46333c Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 14:00:27 -0500 Subject: [PATCH 17/48] fix typo --- src/Database/Relations/AttachOneOrMany.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index f26a67391..69849b1cc 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -209,7 +209,7 @@ public function add(Model $model, $sessionKey = null) * * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { * $relatedClass = get_class($relatedModel); - * $modelClass = get_class($relatedModel); + * $modelClass = get_class($model); * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); * }); * From 24870fc8c51064beea4b0ce3be8353222c0b311d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 6 Nov 2020 13:33:38 -0500 Subject: [PATCH 18/48] add remainging events --- src/Database/Relations/AttachOneOrMany.php | 34 +++++++++++- src/Database/Relations/HasOneOrMany.php | 59 +++++++++++++++++++++ src/Database/Relations/MorphOneOrMany.php | 60 ++++++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index 69849b1cc..92e251ac8 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -168,7 +168,7 @@ public function add(Model $model, $sessionKey = null) if ($sessionKey === null) { /** * @event model.relation.beforeAdd - * Called before adding a relation to the model (only for AttachOne/AttachMany relations) + * Called before adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) * * Example usage: * @@ -203,7 +203,7 @@ public function add(Model $model, $sessionKey = null) /** * @event model.relation.afterAdd - * Called after adding a relation to the model (only for AttachOne/AttachMany relations) + * Called after adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) * * Example usage: * @@ -239,6 +239,21 @@ public function addMany($models, $sessionKey = null) public function remove(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeRemove + * Called before removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $options = $this->parent->getRelationDefinition($this->relationName); if (array_get($options, 'delete', false)) { @@ -263,6 +278,21 @@ public function remove(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterRemove + * Called after removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was removed from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); diff --git a/src/Database/Relations/HasOneOrMany.php b/src/Database/Relations/HasOneOrMany.php index 7d2325257..f8c541ad5 100644 --- a/src/Database/Relations/HasOneOrMany.php +++ b/src/Database/Relations/HasOneOrMany.php @@ -56,6 +56,21 @@ public function create(array $attributes = [], $sessionKey = null) public function add(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeAdd + * Called before adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); if (!$model->exists || $model->isDirty()) { @@ -71,6 +86,21 @@ public function add(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterAdd + * Called after adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -95,6 +125,21 @@ public function addMany($models, $sessionKey = null) public function remove(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeRemove + * Called before removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $model->setAttribute($this->getForeignKeyName(), null); $model->save(); @@ -107,6 +152,20 @@ public function remove(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + /** + * @event model.relation.afterRemove + * Called after removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was removed from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); diff --git a/src/Database/Relations/MorphOneOrMany.php b/src/Database/Relations/MorphOneOrMany.php index 552b1a1d9..a56849ddf 100644 --- a/src/Database/Relations/MorphOneOrMany.php +++ b/src/Database/Relations/MorphOneOrMany.php @@ -45,6 +45,21 @@ public function create(array $attributes = [], $sessionKey = null) public function add(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeAdd + * Called before adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); $model->setAttribute($this->getMorphType(), $this->morphClass); $model->save(); @@ -58,6 +73,21 @@ public function add(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterAdd + * Called after adding a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -70,6 +100,21 @@ public function add(Model $model, $sessionKey = null) public function remove(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeRemove + * Called before removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $options = $this->parent->getRelationDefinition($this->relationName); if (array_get($options, 'delete', false)) { @@ -93,6 +138,21 @@ public function remove(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterRemove + * Called after removing a relation to the model (for AttachOneOrMany, HasOneOrMany & MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was removed from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); From 5c73f26ff4362a03cd24e0512afd31cdfe162b78 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 11:16:02 -0500 Subject: [PATCH 19/48] call parent::attach() instead of duplicating code here --- src/Database/Relations/BelongsToMany.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index d76cd9281..59bfccad3 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -129,14 +129,10 @@ public function attach($id, array $attributes = [], $touch = true) */ $this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData]); - // Here we will insert the attachment records into the pivot table. Once we have - // inserted the records, we will touch the relationships if necessary and the - // function will return. We can parse the IDs before inserting the records. - $this->newPivotStatement()->insert($insertData); - - if ($touch) { - $this->touchIfTouching(); - } + /* + * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable + */ + $result = parent::attach($ids, $attributes, $touch); /** * @event model.relation.afterAttach From 36a6344173db936cb53073e8bf1da3af9e0982b1 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 11:42:09 -0500 Subject: [PATCH 20/48] belongsto and morphto associate() methods have potentially different arguments signature --- src/Database/Relations/BelongsTo.php | 86 +++++++++++++++++++++++++++- src/Database/Relations/MorphTo.php | 86 +++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index da5373b38..4a33171f4 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -8,7 +8,6 @@ class BelongsTo extends BelongsToBase { use DeferOneOrMany; use DefinedConstraints; - use BelongsOrMorphTo; /** * @var string The "name" of the relationship. @@ -50,6 +49,91 @@ public function remove(Model $model, $sessionKey = null) } } + /** + * Associate the model instance to the given parent. + * + * @param \Illuminate\Database\Eloquent\Model|int|string $model + * @return \Illuminate\Database\Eloquent\Model + */ + public function associate($model) + { + /** + * @event model.relation.beforeAssociate + * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); + + $result = parent::associate($model); + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + + return $result; + } + + /** + * Dissociate previously dissociated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() + { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); + + $result = parent::dissociate(); + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was dissociated from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + + return $result; + } + /** * Helper for setting this relationship using various expected * values. For example, $model->relation = $value; diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index dd7ec8ec0..a06dd3316 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -7,7 +7,6 @@ class MorphTo extends MorphToBase { use DefinedConstraints; - use BelongsOrMorphTo; /** * @var string The "name" of the relationship. @@ -23,6 +22,91 @@ public function __construct(Builder $query, Model $parent, $foreignKey, $otherKe $this->addDefinedConstraints(); } + /** + * Associate the model instance to the given parent. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @return \Illuminate\Database\Eloquent\Model + */ + public function associate($model) + { + /** + * @event model.relation.beforeAssociate + * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); + + $result = parent::associate($model); + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + + return $result; + } + + /** + * Dissociate previously dissociated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() + { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); + + $result = parent::dissociate(); + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was dissociated from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + + return $result; + } + /** * Helper for setting this relationship using various expected * values. For example, $model->relation = $value; From 6d333b9c6c94fa772a310200140f4dcdc465d96e Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 11:45:30 -0500 Subject: [PATCH 21/48] not needed, code moved to each relations --- src/Database/Relations/BelongsOrMorphTo.php | 89 --------------------- 1 file changed, 89 deletions(-) delete mode 100644 src/Database/Relations/BelongsOrMorphTo.php diff --git a/src/Database/Relations/BelongsOrMorphTo.php b/src/Database/Relations/BelongsOrMorphTo.php deleted file mode 100644 index 27c07c256..000000000 --- a/src/Database/Relations/BelongsOrMorphTo.php +++ /dev/null @@ -1,89 +0,0 @@ -bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * if ($relationName === 'dummyRelation') { - * throw new \Exception("Invalid relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); - - $result = parent::associate($model); - - /** - * @event model.relation.afterAssociate - * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * $relatedClass = get_class($relatedModel); - * $modelClass = get_class($model); - * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); - - return $result; - } - - /** - * Dissociate previously dissociated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function dissociate() - { - /** - * @event model.relation.beforeDissociate - * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * if ($relationName === 'permanentRelation') { - * throw new \Exception("Cannot dissociate a permanent relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); - - $result = parent::dissociate(); - - /** - * @event model.relation.afterDissociate - * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * $relatedClass = get_class($relatedModel); - * $modelClass = get_class($model); - * traceLog("{$relatedClass} was dissociated from {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); - - return $result; - } -} From 69019c01da0067e7f6c8e5e7f8a640c33e2d8e76 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 12:13:08 -0500 Subject: [PATCH 22/48] properly pass the related model when firing the event --- src/Database/Relations/BelongsTo.php | 4 ++-- src/Database/Relations/HasOneOrMany.php | 8 ++++---- src/Database/Relations/MorphOneOrMany.php | 8 ++++---- src/Database/Relations/MorphTo.php | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index 4a33171f4..cb078def9 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -70,7 +70,7 @@ public function associate($model) * }); * */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $model]); $result = parent::associate($model); @@ -87,7 +87,7 @@ public function associate($model) * }); * */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $model]); return $result; } diff --git a/src/Database/Relations/HasOneOrMany.php b/src/Database/Relations/HasOneOrMany.php index f8c541ad5..fd3283168 100644 --- a/src/Database/Relations/HasOneOrMany.php +++ b/src/Database/Relations/HasOneOrMany.php @@ -69,7 +69,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $model]); $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); @@ -100,7 +100,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $model]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -138,7 +138,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $model]); $model->setAttribute($this->getForeignKeyName(), null); $model->save(); @@ -165,7 +165,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $model]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); diff --git a/src/Database/Relations/MorphOneOrMany.php b/src/Database/Relations/MorphOneOrMany.php index a56849ddf..26f763581 100644 --- a/src/Database/Relations/MorphOneOrMany.php +++ b/src/Database/Relations/MorphOneOrMany.php @@ -58,7 +58,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $model]); $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); $model->setAttribute($this->getMorphType(), $this->morphClass); @@ -87,7 +87,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $model]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -113,7 +113,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $model]); $options = $this->parent->getRelationDefinition($this->relationName); @@ -152,7 +152,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $model]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index a06dd3316..f362e453b 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -43,7 +43,7 @@ public function associate($model) * }); * */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $model]); $result = parent::associate($model); From 70bff296ac5ee3b07da67e70dc0620babb95c6b9 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 17:26:44 -0500 Subject: [PATCH 23/48] remove relatedModel event argument for dissociate() --- src/Database/Relations/BelongsTo.php | 11 +++++------ src/Database/Relations/MorphTo.php | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index cb078def9..4983931cb 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -105,14 +105,14 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } * }); * */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName]); $result = parent::dissociate(); @@ -122,14 +122,13 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * $relatedClass = get_class($relatedModel); + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { * $modelClass = get_class($model); - * traceLog("{$relatedClass} was dissociated from {$modelClass}."); + * traceLog("{$relationName} was dissociated from {$modelClass}."); * }); * */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName]); return $result; } diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index f362e453b..89d3b6de9 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -78,14 +78,14 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } * }); * */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName]); $result = parent::dissociate(); @@ -95,14 +95,13 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { - * $relatedClass = get_class($relatedModel); + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { * $modelClass = get_class($model); - * traceLog("{$relatedClass} was dissociated from {$modelClass}."); + * traceLog("{$relationName} was dissociated from {$modelClass}."); * }); * */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName]); return $result; } From 5142160bb919ab58a3dd650df98263d217691d7f Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 9 Nov 2020 06:36:13 -0500 Subject: [PATCH 24/48] properly pass the related model when firing the event --- src/Database/Relations/AttachOneOrMany.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index 92e251ac8..d7dd1fd9b 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -179,7 +179,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->model]); // Delete siblings for single attachments if ($this instanceof AttachOne) { @@ -214,7 +214,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->model]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -252,7 +252,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->model]); $options = $this->parent->getRelationDefinition($this->relationName); @@ -292,7 +292,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->model]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); From 4601ae3900276455e26434d002e6dfeb218821b8 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 9 Nov 2020 09:29:57 -0500 Subject: [PATCH 25/48] use $model method argument, not $this->model --- src/Database/Relations/AttachOneOrMany.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database/Relations/AttachOneOrMany.php b/src/Database/Relations/AttachOneOrMany.php index d7dd1fd9b..7bb8234d1 100644 --- a/src/Database/Relations/AttachOneOrMany.php +++ b/src/Database/Relations/AttachOneOrMany.php @@ -179,7 +179,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $this->model]); + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $model]); // Delete siblings for single attachments if ($this instanceof AttachOne) { @@ -214,7 +214,7 @@ public function add(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $this->model]); + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $model]); } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); @@ -252,7 +252,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $this->model]); + $this->parent->fireEvent('model.relation.beforeRemove', [$this->relationName, $model]); $options = $this->parent->getRelationDefinition($this->relationName); @@ -292,7 +292,7 @@ public function remove(Model $model, $sessionKey = null) * }); * */ - $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $this->model]); + $this->parent->fireEvent('model.relation.afterRemove', [$this->relationName, $model]); } else { $this->parent->unbindDeferred($this->relationName, $model, $sessionKey); From 1812390a7fe28d88cb76e18b6023b3ae4221def6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 9 Nov 2020 11:06:11 -0500 Subject: [PATCH 26/48] fix related model --- src/Database/Relations/MorphTo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index 89d3b6de9..79d41b4c2 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -60,7 +60,7 @@ public function associate($model) * }); * */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $this->related]); + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $model]); return $result; } From 1c62d591b63c1b866e9f701eb5f23ff8f96845ff Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 21 Nov 2020 10:06:55 -0500 Subject: [PATCH 27/48] no result returned from parent --- src/Database/Relations/BelongsToMany.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index a8c741519..05d5e6c9a 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -132,7 +132,7 @@ public function attach($id, array $attributes = [], $touch = true) /* * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable */ - $result = parent::attach($ids, $attributes, $touch); + parent::attach($ids, $attributes, $touch); /** * @event model.relation.afterAttach From 3d090077b9042adba6bb15b28523c0e5079748e3 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 21 Nov 2020 10:11:24 -0500 Subject: [PATCH 28/48] fix typo --- src/Database/Relations/BelongsToMany.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 05d5e6c9a..879f94d4e 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -132,7 +132,7 @@ public function attach($id, array $attributes = [], $touch = true) /* * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable */ - parent::attach($ids, $attributes, $touch); + parent::attach($id, $attributes, $touch); /** * @event model.relation.afterAttach From 51698b6f7c2fcac2b5413f04540dfa2665cc7c50 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 8 Feb 2021 00:21:24 -0500 Subject: [PATCH 29/48] Update src/Database/Relations/BelongsToMany.php Co-authored-by: Ben Thomson --- src/Database/Relations/BelongsToMany.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 429c906e0..475e827cc 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -141,8 +141,8 @@ public function attach($id, array $attributes = [], $touch = true) */ $this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData]); - /* - * @See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable + /** + * @see \Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable */ parent::attach($id, $attributes, $touch); From 11af5325b92d1e2efb827644bc5f819642bdc969 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 29 Mar 2022 14:08:57 -0400 Subject: [PATCH 30/48] fix namespace --- src/Database/Traits/SortableRelation.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index ae03f6a88..8cfac9f54 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -1,7 +1,7 @@ - 'sort_order_column']; * From cc47e2b98b59cfb2a604888f9247514dba446a48 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Thu, 31 Mar 2022 07:34:56 -0400 Subject: [PATCH 31/48] make it work for one to many relations as well --- src/Database/Traits/SortableRelation.php | 40 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index 8cfac9f54..17984c8ea 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -37,27 +37,30 @@ public function initializeSortableRelation() $this->bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) { if (array_key_exists($relationName, $this->getSortableRelations())) { $column = $this->getRelationSortOrderColumn($relationName); - - $order = $this->$relationName()->max($column); + $relation = $this->$relationName(); + $order = $relation->max($column); foreach ($attached as $id) { $order++; - $this->$relationName()->updateExistingPivot($id, [$column => $order]); + $this->updateRelationOrder($relation, $id, $column, $order); } } }); // Make sure all defined sortable relations load the sort_order column as pivot data. foreach ($this->getSortableRelations() as $relationName => $column) { - $definition = $this->getRelationDefinition($relationName); - $pivot = array_wrap(array_get($definition, 'pivot', [])); + $relation = $this->$relationName(); + if (method_exists($relation, 'updateExistingPivot')) { + $definition = $this->getRelationDefinition($relationName); + $pivot = array_wrap(array_get($definition, 'pivot', [])); - if (!in_array($column, $pivot)) { - $pivot[] = $column; - $definition['pivot'] = $pivot; + if (!in_array($column, $pivot)) { + $pivot[] = $column; + $definition['pivot'] = $pivot; - $relationType = $this->getRelationType($relationName); - $this->$relationType[$relationName] = $definition; + $relationType = $this->getRelationType($relationName); + $this->$relationType[$relationName] = $definition; + } } } } @@ -84,12 +87,23 @@ public function setRelationOrder($relationName, $itemIds, $itemOrders = null) throw new Exception('Invalid setRelationOrder call - count of itemIds do not match count of itemOrders'); } + $column = $this->getRelationSortOrderColumn($relationName); + foreach ($itemIds as $index => $id) { + $relation = $this->$relationName(); $order = $itemOrders[$index]; + $this->updateRelationOrder($relation, $id, $column, $order); + } + } - $this->$relationName()->updateExistingPivot($id, [ - $this->getRelationSortOrderColumn($relationName) => (int)$order - ]); + public function updateRelationOrder($relation, $id, $column, $order) + { + if (method_exists($relation , 'updateExistingPivot')) { + $relation->updateExistingPivot($id, [ $column => (int)$order ]); + } else { + $record = $relation->find($id); + $record->sort_order = $order; + $record->save(); } } From 911d08a303adc83993faf062ea15fa6e8b1e96b4 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Thu, 31 Mar 2022 08:02:14 -0400 Subject: [PATCH 32/48] remove extra space --- src/Database/Traits/SortableRelation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index 17984c8ea..9fbe062e5 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -98,7 +98,7 @@ public function setRelationOrder($relationName, $itemIds, $itemOrders = null) public function updateRelationOrder($relation, $id, $column, $order) { - if (method_exists($relation , 'updateExistingPivot')) { + if (method_exists($relation, 'updateExistingPivot')) { $relation->updateExistingPivot($id, [ $column => (int)$order ]); } else { $record = $relation->find($id); From 84f018f81b5abc783be230c09b1a6501eb02e621 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 1 Apr 2022 10:43:21 -0400 Subject: [PATCH 33/48] simplify code a bit; assign default order when undefined --- src/Database/Traits/SortableRelation.php | 49 +++++++++++------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index 9fbe062e5..e0b109e30 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -1,7 +1,6 @@ bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) { + // won't work for HasMany relations as this event is only fired for pivot based relations if (array_key_exists($relationName, $this->getSortableRelations())) { $column = $this->getRelationSortOrderColumn($relationName); - $relation = $this->$relationName(); - $order = $relation->max($column); foreach ($attached as $id) { - $order++; - $this->updateRelationOrder($relation, $id, $column, $order); + $this->updateRelationOrder($relationName, $id, $column); } } }); @@ -50,6 +46,7 @@ public function initializeSortableRelation() // Make sure all defined sortable relations load the sort_order column as pivot data. foreach ($this->getSortableRelations() as $relationName => $column) { $relation = $this->$relationName(); + // only for pivot based relations if (method_exists($relation, 'updateExistingPivot')) { $definition = $this->getRelationDefinition($relationName); $pivot = array_wrap(array_get($definition, 'pivot', [])); @@ -66,20 +63,16 @@ public function initializeSortableRelation() } /** - * Sets the sort order of records to the specified orders. If the orders is + * Set the sort order of records to the specified orders. If the orders is * undefined, the record identifier is used. - * @param string $relation - * @param mixed $itemIds - * @param array $itemOrders - * @return void */ - public function setRelationOrder($relationName, $itemIds, $itemOrders = null) + public function setRelationOrder(string $relationName, string|int|array $itemIds, array $itemOrders = []) : void { if (!is_array($itemIds)) { $itemIds = [$itemIds]; } - if ($itemOrders === null) { + if (empty($itemOrders)) { $itemOrders = $itemIds; } @@ -90,38 +83,42 @@ public function setRelationOrder($relationName, $itemIds, $itemOrders = null) $column = $this->getRelationSortOrderColumn($relationName); foreach ($itemIds as $index => $id) { - $relation = $this->$relationName(); - $order = $itemOrders[$index]; - $this->updateRelationOrder($relation, $id, $column, $order); + $order = (int)$itemOrders[$index]; + $this->updateRelationOrder($relationName, $id, $column, $order); } } - public function updateRelationOrder($relation, $id, $column, $order) + /** + * Update relation record sort_order. + */ + protected function updateRelationOrder(string $relationName, int $id, string $column, int $order = 0) : void { + $relation = $this->$relationName(); + + if (!$order) { + $order = $relation->max($column) + 1; + } if (method_exists($relation, 'updateExistingPivot')) { $relation->updateExistingPivot($id, [ $column => (int)$order ]); } else { $record = $relation->find($id); - $record->sort_order = $order; + $record->sort_order = (int)$order; $record->save(); } } /** * Get the name of the "sort_order" column. - * @param string $relation - * @return string */ - public function getRelationSortOrderColumn($relation) + public function getRelationSortOrderColumn(string $relationName) : string { - return $this->getSortableRelations()[$relation] ?? 'sort_order'; + return $this->getSortableRelations()[$relationName] ?? 'sort_order'; } /** - * Returns all configured sortable relations. - * @return array + * Return all configured sortable relations. */ - protected function getSortableRelations() + protected function getSortableRelations() : array { if (property_exists($this, 'sortableRelations')) { return $this->sortableRelations; From b3022d4efd40d6b1290dfc59bc1222e35deebce6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 1 Apr 2022 12:48:41 -0400 Subject: [PATCH 34/48] fix non pivot-based relation records initialization --- src/Database/Traits/SortableRelation.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index e0b109e30..e98a57465 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -32,9 +32,11 @@ trait SortableRelation */ public function initializeSortableRelation() : void { + $sortableRelations = $this->getSortableRelations(); + $this->bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) { - // won't work for HasMany relations as this event is only fired for pivot based relations - if (array_key_exists($relationName, $this->getSortableRelations())) { + // Only for pivot-based relations + if (array_key_exists($relationName, $sortableRelations)) { $column = $this->getRelationSortOrderColumn($relationName); foreach ($attached as $id) { @@ -43,11 +45,10 @@ public function initializeSortableRelation() : void } }); - // Make sure all defined sortable relations load the sort_order column as pivot data. - foreach ($this->getSortableRelations() as $relationName => $column) { + foreach ($sortableRelations as $relationName => $column) { $relation = $this->$relationName(); - // only for pivot based relations if (method_exists($relation, 'updateExistingPivot')) { + // Make sure all pivot-based defined sortable relations load the sort_order column as pivot data. $definition = $this->getRelationDefinition($relationName); $pivot = array_wrap(array_get($definition, 'pivot', [])); @@ -58,6 +59,17 @@ public function initializeSortableRelation() : void $relationType = $this->getRelationType($relationName); $this->$relationType[$relationName] = $definition; } + } else { + // For NON pivot-based relations + $model = $relation->getModel(); + $model::extend(function ($model) use ($relationName, $column) { + $model->bindEvent('model.beforeSave', function () use ($model, $relationName, $column) { + // initialize sort_order as max + 1 + $relation = $this->$relationName(); + $order = $relation->max($column) + 1; + $model->$column = $order; + }); + }); } } } From aaea530e1fb5013c1251cfee9eef4461cf3aa082 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 1 Apr 2022 13:02:10 -0400 Subject: [PATCH 35/48] use more appropriate model.beforeCreate event --- src/Database/Traits/SortableRelation.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index e98a57465..5d19122b7 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -61,9 +61,9 @@ public function initializeSortableRelation() : void } } else { // For NON pivot-based relations - $model = $relation->getModel(); - $model::extend(function ($model) use ($relationName, $column) { - $model->bindEvent('model.beforeSave', function () use ($model, $relationName, $column) { + $relatedModel = $relation->getRelated(); + $relatedModel::extend(function ($model) use ($relationName, $column) { + $model->bindEvent('model.beforeCreate', function () use ($model, $relationName, $column) { // initialize sort_order as max + 1 $relation = $this->$relationName(); $order = $relation->max($column) + 1; From 910796416faff089b7415cb7c6921dbdfe3407da Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 1 Apr 2022 13:45:25 -0400 Subject: [PATCH 36/48] extend the class, not the instance --- src/Database/Traits/SortableRelation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/SortableRelation.php index 5d19122b7..fd0b4df1d 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/SortableRelation.php @@ -61,8 +61,8 @@ public function initializeSortableRelation() : void } } else { // For NON pivot-based relations - $relatedModel = $relation->getRelated(); - $relatedModel::extend(function ($model) use ($relationName, $column) { + $relatedClass = get_class($relation->getRelated()); + $relatedClass::extend(function ($model) use ($relationName, $column) { $model->bindEvent('model.beforeCreate', function () use ($model, $relationName, $column) { // initialize sort_order as max + 1 $relation = $this->$relationName(); From aba5b17072b4a7c6a1a317eede06c8db6c812c77 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 1 Apr 2022 17:44:51 -0400 Subject: [PATCH 37/48] rename to more correct "HasSortableRelations" --- ...SortableRelation.php => HasSortableRelations.php} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename src/Database/Traits/{SortableRelation.php => HasSortableRelations.php} (93%) diff --git a/src/Database/Traits/SortableRelation.php b/src/Database/Traits/HasSortableRelations.php similarity index 93% rename from src/Database/Traits/SortableRelation.php rename to src/Database/Traits/HasSortableRelations.php index fd0b4df1d..7a610fb02 100644 --- a/src/Database/Traits/SortableRelation.php +++ b/src/Database/Traits/HasSortableRelations.php @@ -3,13 +3,13 @@ use Exception; /** - * SortableRelation model trait + * HasSortableRelations trait * * Usage: * * In the model class definition add: * - * use \Winter\Storm\Database\Traits\SortableRelation; + * use \Winter\Storm\Database\Traits\HasSortableRelations; * * public $sortableRelations = ['relation_name' => 'sort_order_column']; * @@ -18,7 +18,7 @@ * $model->setSortableRelationOrder($relationName, $recordIds, $recordOrders); * */ -trait SortableRelation +trait HasSortableRelations { /** * @var array The array of all sortable relations with their sort_order pivot column. @@ -27,10 +27,10 @@ trait SortableRelation */ /** - * Boot the SortableRelation trait for this model. - * Make sure to add the sort_order value if a related model has been attached. + * Initialize the HasSortableRelations trait for this model. + * Sets the sort_order value if a related model has been attached. */ - public function initializeSortableRelation() : void + public function initializeHasSortableRelations() : void { $sortableRelations = $this->getSortableRelations(); From 94993a06def2a954c5e2e29746907bf4a6c30c20 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 8 Apr 2022 12:28:02 -0400 Subject: [PATCH 38/48] make $sortableRelations visible in closure --- src/Database/Traits/HasSortableRelations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Traits/HasSortableRelations.php b/src/Database/Traits/HasSortableRelations.php index 7a610fb02..a9272d918 100644 --- a/src/Database/Traits/HasSortableRelations.php +++ b/src/Database/Traits/HasSortableRelations.php @@ -34,7 +34,7 @@ public function initializeHasSortableRelations() : void { $sortableRelations = $this->getSortableRelations(); - $this->bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) { + $this->bindEvent('model.relation.afterAttach', function ($relationName, $attached, $data) use ($sortableRelations) { // Only for pivot-based relations if (array_key_exists($relationName, $sortableRelations)) { $column = $this->getRelationSortOrderColumn($relationName); From 813cb08c98da18fbdb70087527567e6d23774cc4 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 3 Jun 2022 20:47:43 -0400 Subject: [PATCH 39/48] use the new model.relation.afterAdd event --- src/Database/Traits/HasSortableRelations.php | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Database/Traits/HasSortableRelations.php b/src/Database/Traits/HasSortableRelations.php index a9272d918..c3a65ba3b 100644 --- a/src/Database/Traits/HasSortableRelations.php +++ b/src/Database/Traits/HasSortableRelations.php @@ -45,6 +45,15 @@ public function initializeHasSortableRelations() : void } }); + $this->bindEvent('model.relation.afterAdd', function ($relationName, $relatedModel) use ($sortableRelations) { + // Only for non pivot-based relations + if (array_key_exists($relationName, $sortableRelations)) { + $column = $this->getRelationSortOrderColumn($relationName); + + $this->updateRelationOrder($relationName, $relatedModel->id, $column); + } + }); + foreach ($sortableRelations as $relationName => $column) { $relation = $this->$relationName(); if (method_exists($relation, 'updateExistingPivot')) { @@ -59,17 +68,6 @@ public function initializeHasSortableRelations() : void $relationType = $this->getRelationType($relationName); $this->$relationType[$relationName] = $definition; } - } else { - // For NON pivot-based relations - $relatedClass = get_class($relation->getRelated()); - $relatedClass::extend(function ($model) use ($relationName, $column) { - $model->bindEvent('model.beforeCreate', function () use ($model, $relationName, $column) { - // initialize sort_order as max + 1 - $relation = $this->$relationName(); - $order = $relation->max($column) + 1; - $model->$column = $order; - }); - }); } } } @@ -105,16 +103,16 @@ public function setRelationOrder(string $relationName, string|int|array $itemIds */ protected function updateRelationOrder(string $relationName, int $id, string $column, int $order = 0) : void { - $relation = $this->$relationName(); + $relation = $this->{$relationName}(); if (!$order) { - $order = $relation->max($column) + 1; + $order = $relation->count(); } if (method_exists($relation, 'updateExistingPivot')) { $relation->updateExistingPivot($id, [ $column => (int)$order ]); } else { $record = $relation->find($id); - $record->sort_order = (int)$order; + $record->{$column} = (int)$order; $record->save(); } } From 580fef6945cc54e36cef80103a12c82543c3862f Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 3 Jun 2022 20:51:20 -0400 Subject: [PATCH 40/48] add model.relation.{before,after}Add events to morphOneOrMany relations --- src/Database/Relations/MorphOneOrMany.php | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Database/Relations/MorphOneOrMany.php b/src/Database/Relations/MorphOneOrMany.php index 43c1b3c58..b98fff84d 100644 --- a/src/Database/Relations/MorphOneOrMany.php +++ b/src/Database/Relations/MorphOneOrMany.php @@ -45,6 +45,21 @@ public function create(array $attributes = [], $sessionKey = null) public function add(Model $model, $sessionKey = null) { if ($sessionKey === null) { + /** + * @event model.relation.beforeAdd + * Called before adding a relation to the model (MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAdd', [$this->relationName, $model]); + $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); $model->setAttribute($this->getMorphType(), $this->morphClass); $model->save(); @@ -58,6 +73,22 @@ public function add(Model $model, $sessionKey = null) else { $this->parent->reloadRelations($this->relationName); } + + /** + * @event model.relation.afterAdd + * Called after adding a relation to the model (MorphOneOrMany relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $model]); + } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); From 12d1acb224a9a564826ad80be7484d981eb435f9 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 3 Jun 2022 21:20:39 -0400 Subject: [PATCH 41/48] fix code smell --- src/Database/Relations/MorphOneOrMany.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Database/Relations/MorphOneOrMany.php b/src/Database/Relations/MorphOneOrMany.php index b98fff84d..091add477 100644 --- a/src/Database/Relations/MorphOneOrMany.php +++ b/src/Database/Relations/MorphOneOrMany.php @@ -88,7 +88,6 @@ public function add(Model $model, $sessionKey = null) * */ $this->parent->fireEvent('model.relation.afterAdd', [$this->relationName, $model]); - } else { $this->parent->bindDeferred($this->relationName, $model, $sessionKey); From 9ffefcd78f7d91ceb52cb64da998c76f64ceca93 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Wed, 6 Jul 2022 16:02:35 +0800 Subject: [PATCH 42/48] Fix code analysis errors --- phpstan-baseline.neon | 5 ----- src/Database/Relations/BelongsTo.php | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index fd99a24a5..b50ce78ce 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -260,11 +260,6 @@ parameters: count: 1 path: src/Database/Relations/BelongsTo.php - - - message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:getRelationDefinition\\(\\)\\.$#" - count: 3 - path: src/Database/Relations/BelongsTo.php - - message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation\\:\\:getForeignKey\\(\\)\\.$#" count: 3 diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index b5d68e031..b20372a61 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -6,6 +6,7 @@ /** * @phpstan-property \Winter\Storm\Database\Model $child + * @phpstan-property \Winter\Storm\Database\Model $parent */ class BelongsTo extends BelongsToBase { From fd7ac923787735066090b8f27d17972aef6c9e41 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 09:46:24 -0400 Subject: [PATCH 43/48] remap October\Rain to Winter\Storm --- src/Database/Relations/BelongsTo.php | 8 ++++---- src/Database/Relations/Concerns/AttachOneOrMany.php | 8 ++++---- src/Database/Relations/Concerns/HasOneOrMany.php | 8 ++++---- src/Database/Relations/Concerns/MorphOneOrMany.php | 8 ++++---- src/Database/Relations/MorphTo.php | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index b20372a61..e2576ff74 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -67,7 +67,7 @@ public function associate($model) * * Example usage: * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'dummyRelation') { * throw new \Exception("Invalid relation!"); * } @@ -84,7 +84,7 @@ public function associate($model) * * Example usage: * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); @@ -109,7 +109,7 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } @@ -126,7 +126,7 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { * $modelClass = get_class($model); * traceLog("{$relationName} was dissociated from {$modelClass}."); * }); diff --git a/src/Database/Relations/Concerns/AttachOneOrMany.php b/src/Database/Relations/Concerns/AttachOneOrMany.php index f90f10ea4..22e761e44 100644 --- a/src/Database/Relations/Concerns/AttachOneOrMany.php +++ b/src/Database/Relations/Concerns/AttachOneOrMany.php @@ -173,7 +173,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'dummyRelation') { * throw new \Exception("Invalid relation!"); * } @@ -208,7 +208,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); @@ -246,7 +246,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } @@ -286,7 +286,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was removed from {$modelClass}."); diff --git a/src/Database/Relations/Concerns/HasOneOrMany.php b/src/Database/Relations/Concerns/HasOneOrMany.php index b27eb5978..918604cb9 100644 --- a/src/Database/Relations/Concerns/HasOneOrMany.php +++ b/src/Database/Relations/Concerns/HasOneOrMany.php @@ -63,7 +63,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'dummyRelation') { * throw new \Exception("Invalid relation!"); * } @@ -94,7 +94,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); @@ -132,7 +132,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } @@ -159,7 +159,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was removed from {$modelClass}."); diff --git a/src/Database/Relations/Concerns/MorphOneOrMany.php b/src/Database/Relations/Concerns/MorphOneOrMany.php index 7e9880579..6add0dcb4 100644 --- a/src/Database/Relations/Concerns/MorphOneOrMany.php +++ b/src/Database/Relations/Concerns/MorphOneOrMany.php @@ -51,7 +51,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'dummyRelation') { * throw new \Exception("Invalid relation!"); * } @@ -80,7 +80,7 @@ public function add(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterAdd', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was added as {$relationName} to {$modelClass}."); @@ -106,7 +106,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } @@ -145,7 +145,7 @@ public function remove(Model $model, $sessionKey = null) * * Example usage: * - * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterRemove', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was removed from {$modelClass}."); diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index b159cfde2..19436e907 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -40,7 +40,7 @@ public function associate($model) * * Example usage: * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'dummyRelation') { * throw new \Exception("Invalid relation!"); * } @@ -57,7 +57,7 @@ public function associate($model) * * Example usage: * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \October\Rain\Database\Model $relatedModel) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { * $relatedClass = get_class($relatedModel); * $modelClass = get_class($model); * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); @@ -82,7 +82,7 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { * if ($relationName === 'permanentRelation') { * throw new \Exception("Cannot dissociate a permanent relation!"); * } @@ -99,7 +99,7 @@ public function dissociate() * * Example usage: * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\October\Rain\Database\Model $model) { + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { * $modelClass = get_class($model); * traceLog("{$relationName} was dissociated from {$modelClass}."); * }); From 8bb1a7e4c81999c4782a14fb5dc66d3d1d831e3d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 10:00:04 -0400 Subject: [PATCH 44/48] move shared methods to new BelongsOrMorphsTo trait --- src/Database/Relations/BelongsTo.php | 85 +---------------- .../Relations/Concerns/BelongsOrMorphsTo.php | 91 +++++++++++++++++++ src/Database/Relations/MorphTo.php | 85 +---------------- 3 files changed, 93 insertions(+), 168 deletions(-) create mode 100644 src/Database/Relations/Concerns/BelongsOrMorphsTo.php diff --git a/src/Database/Relations/BelongsTo.php b/src/Database/Relations/BelongsTo.php index e2576ff74..1a133f6b1 100644 --- a/src/Database/Relations/BelongsTo.php +++ b/src/Database/Relations/BelongsTo.php @@ -10,6 +10,7 @@ */ class BelongsTo extends BelongsToBase { + use Concerns\BelongsOrMorphsTo; use Concerns\DeferOneOrMany; use Concerns\DefinedConstraints; @@ -53,90 +54,6 @@ public function remove(Model $model, $sessionKey = null) } } - /** - * Associate the model instance to the given parent. - * - * @param \Illuminate\Database\Eloquent\Model|int|string $model - * @return \Illuminate\Database\Eloquent\Model - */ - public function associate($model) - { - /** - * @event model.relation.beforeAssociate - * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { - * if ($relationName === 'dummyRelation') { - * throw new \Exception("Invalid relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $model]); - - $result = parent::associate($model); - - /** - * @event model.relation.afterAssociate - * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { - * $relatedClass = get_class($relatedModel); - * $modelClass = get_class($model); - * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $model]); - - return $result; - } - - /** - * Dissociate previously dissociated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function dissociate() - { - /** - * @event model.relation.beforeDissociate - * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { - * if ($relationName === 'permanentRelation') { - * throw new \Exception("Cannot dissociate a permanent relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName]); - - $result = parent::dissociate(); - - /** - * @event model.relation.afterDissociate - * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { - * $modelClass = get_class($model); - * traceLog("{$relationName} was dissociated from {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName]); - - return $result; - } - /** * Helper for setting this relationship using various expected * values. For example, $model->relation = $value; diff --git a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php new file mode 100644 index 000000000..eb5ea1651 --- /dev/null +++ b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php @@ -0,0 +1,91 @@ +bindEvent('model.relation.beforeAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { + * if ($relationName === 'dummyRelation') { + * throw new \Exception("Invalid relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $model]); + + $result = parent::associate($model); + + /** + * @event model.relation.afterAssociate + * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { + * $relatedClass = get_class($relatedModel); + * $modelClass = get_class($model); + * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $model]); + + return $result; + } + + /** + * Dissociate previously associated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function dissociate() + { + /** + * @event model.relation.beforeDissociate + * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { + * if ($relationName === 'permanentRelation') { + * throw new \Exception("Cannot dissociate a permanent relation!"); + * } + * }); + * + */ + $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName]); + + $result = parent::dissociate(); + + /** + * @event model.relation.afterDissociate + * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) + * + * Example usage: + * + * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { + * $modelClass = get_class($model); + * traceLog("{$relationName} was dissociated from {$modelClass}."); + * }); + * + */ + $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName]); + + return $result; + } +} + diff --git a/src/Database/Relations/MorphTo.php b/src/Database/Relations/MorphTo.php index 19436e907..229c70efb 100644 --- a/src/Database/Relations/MorphTo.php +++ b/src/Database/Relations/MorphTo.php @@ -9,6 +9,7 @@ */ class MorphTo extends MorphToBase { + use Concerns\BelongsOrMorphsTo; use Concerns\DeferOneOrMany; use Concerns\DefinedConstraints; @@ -26,90 +27,6 @@ public function __construct(Builder $query, Model $parent, $foreignKey, $otherKe $this->addDefinedConstraints(); } - /** - * Associate the model instance to the given parent. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @return \Illuminate\Database\Eloquent\Model - */ - public function associate($model) - { - /** - * @event model.relation.beforeAssociate - * Called before associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { - * if ($relationName === 'dummyRelation') { - * throw new \Exception("Invalid relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeAssociate', [$this->relationName, $model]); - - $result = parent::associate($model); - - /** - * @event model.relation.afterAssociate - * Called after associating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterAssociate', function (string $relationName, \Winter\Storm\Database\Model $relatedModel) use (\Winter\Storm\Database\Model $model) { - * $relatedClass = get_class($relatedModel); - * $modelClass = get_class($model); - * traceLog("{$relatedClass} was associated as {$relationName} to {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterAssociate', [$this->relationName, $model]); - - return $result; - } - - /** - * Dissociate previously dissociated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function dissociate() - { - /** - * @event model.relation.beforeDissociate - * Called before dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.beforeDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { - * if ($relationName === 'permanentRelation') { - * throw new \Exception("Cannot dissociate a permanent relation!"); - * } - * }); - * - */ - $this->parent->fireEvent('model.relation.beforeDissociate', [$this->relationName]); - - $result = parent::dissociate(); - - /** - * @event model.relation.afterDissociate - * Called after dissociating a relation to the model (only for BelongsTo/MorphTo relations) - * - * Example usage: - * - * $model->bindEvent('model.relation.afterDissociate', function (string $relationName) use (\Winter\Storm\Database\Model $model) { - * $modelClass = get_class($model); - * traceLog("{$relationName} was dissociated from {$modelClass}."); - * }); - * - */ - $this->parent->fireEvent('model.relation.afterDissociate', [$this->relationName]); - - return $result; - } - /** * Helper for setting this relationship using various expected * values. For example, $model->relation = $value; From 43c145ade5ea22b49f64c0d976c30eaad7bdd762 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 10:17:36 -0400 Subject: [PATCH 45/48] remove blank line at EOF --- src/Database/Relations/Concerns/BelongsOrMorphsTo.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php index eb5ea1651..97bb85df8 100644 --- a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php +++ b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php @@ -88,4 +88,3 @@ public function dissociate() return $result; } } - From 958fc7b7d880b9ea35d5f025224af4f2f0028adf Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 10:26:44 -0400 Subject: [PATCH 46/48] use method signature --- src/Database/Relations/Concerns/BelongsOrMorphsTo.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php index 97bb85df8..05d98c51e 100644 --- a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php +++ b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php @@ -6,11 +6,8 @@ trait BelongsOrMorphsTo { /** * Associate the model instance to the given parent. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @return \Illuminate\Database\Eloquent\Model */ - public function associate($model) + public function associate(Model $model): Model { /** * @event model.relation.beforeAssociate @@ -49,10 +46,8 @@ public function associate($model) /** * Dissociate previously associated model from the given parent. - * - * @return \Illuminate\Database\Eloquent\Model */ - public function dissociate() + public function dissociate(): Model { /** * @event model.relation.beforeDissociate From 809ce641ccb7052a0b33c77048e33ce1784a2691 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 10:30:44 -0400 Subject: [PATCH 47/48] fix method signature clashes with Laravel signature This reverts commit 958fc7b7d880b9ea35d5f025224af4f2f0028adf. --- src/Database/Relations/Concerns/BelongsOrMorphsTo.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php index 05d98c51e..97bb85df8 100644 --- a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php +++ b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php @@ -6,8 +6,11 @@ trait BelongsOrMorphsTo { /** * Associate the model instance to the given parent. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @return \Illuminate\Database\Eloquent\Model */ - public function associate(Model $model): Model + public function associate($model) { /** * @event model.relation.beforeAssociate @@ -46,8 +49,10 @@ public function associate(Model $model): Model /** * Dissociate previously associated model from the given parent. + * + * @return \Illuminate\Database\Eloquent\Model */ - public function dissociate(): Model + public function dissociate() { /** * @event model.relation.beforeDissociate From f566cda8c3cfb906f46cc9b01af2cba136351bd1 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Jul 2022 10:32:22 -0400 Subject: [PATCH 48/48] no need to Illuminate model --- src/Database/Relations/Concerns/BelongsOrMorphsTo.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php index 97bb85df8..8c51f88ed 100644 --- a/src/Database/Relations/Concerns/BelongsOrMorphsTo.php +++ b/src/Database/Relations/Concerns/BelongsOrMorphsTo.php @@ -1,7 +1,5 @@