Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more relation events #537

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2d1f3f4
add before/after save & create events
mjauvin Oct 27, 2020
da8579d
add before/after associate/dissociate events
mjauvin Oct 27, 2020
73ac6f0
Revert "add before/after save & create events"
mjauvin Oct 27, 2020
766ac61
do not make halting events
mjauvin Oct 28, 2020
8052d98
should not be halting events
mjauvin Oct 30, 2020
7f42aff
return parent results for overriden parent methods
mjauvin Oct 31, 2020
5762c7e
override associate/dissociate and fire before/after events there
mjauvin Nov 1, 2020
93176f3
do not pass true to Event::fire
mjauvin Nov 1, 2020
b33c08b
use a trait to avoid code duplication
mjauvin Nov 1, 2020
b59cf61
remove unused class
mjauvin Nov 1, 2020
5009e87
add example code in docblocks
mjauvin Nov 1, 2020
7e2b6e4
add parent::detach results to event params
mjauvin Nov 1, 2020
4b015d4
add {before,after}Add events to AttachOneOrMany
mjauvin Nov 3, 2020
4538d80
fix examples
mjauvin Nov 3, 2020
40215d0
fix typo
mjauvin Nov 3, 2020
24870fc
add remainging events
mjauvin Nov 6, 2020
5c73f26
call parent::attach() instead of duplicating code here
mjauvin Nov 8, 2020
36a6344
belongsto and morphto associate() methods have potentially different …
mjauvin Nov 8, 2020
6d333b9
not needed, code moved to each relations
mjauvin Nov 8, 2020
69019c0
properly pass the related model when firing the event
mjauvin Nov 8, 2020
70bff29
remove relatedModel event argument for dissociate()
mjauvin Nov 8, 2020
5142160
properly pass the related model when firing the event
mjauvin Nov 9, 2020
4601ae3
use $model method argument, not $this->model
mjauvin Nov 9, 2020
1812390
fix related model
mjauvin Nov 9, 2020
d0a040f
Merge branch 'develop' into add-relation-events
mjauvin Nov 21, 2020
1c62d59
no result returned from parent
mjauvin Nov 21, 2020
3d09007
fix typo
mjauvin Nov 21, 2020
74e1e3a
Merge branch 'develop' into add-relation-events
mjauvin Feb 7, 2021
51698b6
Update src/Database/Relations/BelongsToMany.php
mjauvin Feb 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/Database/Relations/AttachOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 (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, $model]);

// Delete siblings for single attachments
if ($this instanceof AttachOne) {
$this->delete();
Expand All @@ -185,6 +200,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, $model]);
}
else {
$this->parent->bindDeferred($this->relationName, $model, $sessionKey);
Expand All @@ -209,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, $model]);

$options = $this->parent->getRelationDefinition($this->relationName);

if (array_get($options, 'delete', false)) {
Expand All @@ -233,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, $model]);
}
else {
$this->parent->unbindDeferred($this->relationName, $model, $sessionKey);
Expand Down
84 changes: 84 additions & 0 deletions src/Database/Relations/BelongsTo.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,90 @@ 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, $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, \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, $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 (\October\Rain\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 (\October\Rain\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;
Expand Down
29 changes: 15 additions & 14 deletions src/Database/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,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)
{
Expand All @@ -133,17 +135,14 @@ 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;
* }
* });
*
*/
if ($this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData], true) === false) {
return;
}
$this->parent->fireEvent('model.relation.beforeAttach', [$this->relationName, $attachedIdList, $insertData]);

/**
* @see Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable
/*
* @See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
*/
parent::attach($id, $attributes, $touch);

Expand All @@ -164,9 +163,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)
{
Expand All @@ -189,27 +189,28 @@ 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]);
mjauvin marked this conversation as resolved.
Show resolved Hide resolved

/**
* @see Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable
*/
parent::detach($attachedIdList, $touch);

$result = parent::detach($ids, $touch);

/**
* @event model.relation.afterDetach
* Called after removing a relation between models (only for BelongsToMany relation)
*
* 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;
}

/**
Expand Down
59 changes: 59 additions & 0 deletions src/Database/Relations/HasOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -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, $model]);

$model->setAttribute($this->getForeignKeyName(), $this->getParentKey());

if (!$model->exists || $model->isDirty()) {
Expand All @@ -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, $model]);
}
else {
$this->parent->bindDeferred($this->relationName, $model, $sessionKey);
Expand All @@ -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, $model]);

$model->setAttribute($this->getForeignKeyName(), null);
$model->save();

Expand All @@ -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, $model]);
}
else {
$this->parent->unbindDeferred($this->relationName, $model, $sessionKey);
Expand Down
Loading