diff --git a/README.md b/README.md index cf8301f..ad1f2bf 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,14 @@ item, you can just attach the behavior to the related table classes, and set the This works on relationships where the item being deleted in the owning side of the relationship. Which means that the related table should contain the foreign key. +If you don't want to cascade on trash: +```php +// in the initialize() method +$this->addBehavior('Muffin/Trash.Trash', [ + 'cascadeOnTrash' => false, +]); +``` + ### Custom Finders - **onlyTrashed** - helps getting only those trashed records. diff --git a/src/Model/Behavior/TrashBehavior.php b/src/Model/Behavior/TrashBehavior.php index 5af92c3..d6b4b65 100644 --- a/src/Model/Behavior/TrashBehavior.php +++ b/src/Model/Behavior/TrashBehavior.php @@ -43,6 +43,7 @@ class TrashBehavior extends Behavior 'Model.beforeDelete', 'Model.beforeFind', ], + 'cascadeOnTrash' => true, ]; /** @@ -145,10 +146,12 @@ public function trash(EntityInterface $entity, array $options = []): bool } } - $associations = $this->_table->associations()->getByType(['HasOne', 'HasMany']); - foreach ($associations as $association) { - if ($this->_isRecursable($association, $this->_table)) { - $association->cascadeDelete($entity, ['_primary' => false] + $options); + if ($this->getConfig('cascadeOnTrash')) { + $associations = $this->_table->associations()->getByType(['HasOne', 'HasMany']); + foreach ($associations as $association) { + if ($this->_isRecursable($association, $this->_table)) { + $association->cascadeDelete($entity, ['_primary' => false] + $options); + } } } diff --git a/tests/TestCase/Model/Behavior/TrashBehaviorTest.php b/tests/TestCase/Model/Behavior/TrashBehaviorTest.php index d75cb69..e3f886d 100644 --- a/tests/TestCase/Model/Behavior/TrashBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/TrashBehaviorTest.php @@ -526,6 +526,38 @@ public function testCascadingTrash() $this->assertInstanceOf(DateTime::class, $article->comments[0]->trashed); } + /** + * When cascadeTrashAndRestore = false + * Ensure that when trashing it will not cascade into related dependent records + * + * @return void + */ + public function testDisabledCascadingForTrash() + { + $association = $this->Articles->Comments; + $association->setDependent(true); + $association->setCascadeCallbacks(true); + + // disable cascade trash/restore + $this->Articles->behaviors()->get('Trash')->setConfig('cascadeOnTrash', false); + + $article = $this->Articles->get(1); + $this->Articles->trash($article); + + $article = $this->Articles->find('withTrashed') + ->where(['Articles.id' => 1]) + ->contain(['Comments' => [ + 'finder' => 'withTrashed', + ]]) + ->first(); + + $this->assertNotEmpty($article->trashed); + $this->assertInstanceOf(DateTime::class, $article->trashed); + + // expect not trashed + $this->assertEmpty($article->comments[0]->trashed); + } + public function testCascadingUntrashOptionsArePassedToSave() { $association = $this->Articles->Comments;