Skip to content

Commit 49b6ec1

Browse files
committed
working demo
1 parent d560327 commit 49b6ec1

File tree

1 file changed

+127
-6
lines changed

1 file changed

+127
-6
lines changed

tests/RandomTest.php

Lines changed: 127 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ protected function init(): void
2727
}
2828
class Model_Item extends Model
2929
{
30+
use ModelSoftDeleteTrait;
31+
3032
public $table = 'item';
3133

3234
protected function init(): void
@@ -36,6 +38,8 @@ protected function init(): void
3638
$this->addField('name');
3739
$this->hasOne('parent_item_id', ['model' => [self::class]])
3840
->addTitle();
41+
42+
$this->initSoftDelete();
3943
}
4044
}
4145
class Model_Item2 extends Model
@@ -71,6 +75,83 @@ protected function init(): void
7175
}
7276
}
7377

78+
trait ModelSoftDeleteTrait
79+
{
80+
protected function initSoftDelete(): void
81+
{
82+
$this->addField('is_deleted', ['type' => 'boolean', 'nullable' => false, 'default' => false]);
83+
$this->addCondition('is_deleted', false);
84+
$this->onHook(Model::HOOK_BEFORE_DELETE, function (Model $entity) {
85+
$softDeleteController = new ControllerSoftDelete();
86+
$softDeleteController->softDelete($entity);
87+
88+
$entity->hook(Model::HOOK_AFTER_DELETE);
89+
$entity->breakHook(false); // this will cancel original Model::delete()
90+
});
91+
}
92+
}
93+
94+
class ControllerSoftDelete
95+
{
96+
protected function init(): void
97+
{
98+
// example broken for clone "Object cannot be cloned with hook bound to a different object than this"
99+
// TODO remove this code from docs, hard to fix, controller is not meant to be added this way to model
100+
throw new \Error();
101+
}
102+
103+
/**
104+
* @return mixed
105+
*/
106+
public function invokeCallbackWithoutUndeletedCondition(Model $model, \Closure $callback)
107+
{
108+
$model->getField('is_deleted'); // assert field exists
109+
110+
$scopeElementsOrig = $model->scope()->elements;
111+
try {
112+
foreach ($model->scope()->elements as $k => $v) {
113+
if ($v instanceof Model\Scope\Condition && $v->key === 'is_deleted' && $v->operator === '=' && $v->value === false) {
114+
unset($model->scope()->elements[$k]);
115+
}
116+
}
117+
118+
return $callback();
119+
} finally {
120+
$model->scope()->elements = $scopeElementsOrig;
121+
}
122+
}
123+
124+
public function softDelete(Model $entity): void
125+
{
126+
$entity->assertIsLoaded();
127+
128+
$this->invokeCallbackWithoutUndeletedCondition($entity->getModel(), function () use ($entity): void {
129+
if ($entity->hook('beforeSoftDelete') === false) {
130+
return;
131+
}
132+
133+
$entity->saveAndUnload(['is_deleted' => true]);
134+
135+
$entity->hook('afterSoftDelete');
136+
});
137+
}
138+
139+
public function restore(Model $entity): void
140+
{
141+
$entity->assertIsLoaded();
142+
143+
$this->invokeCallbackWithoutUndeletedCondition($entity->getModel(), function () use ($entity): void {
144+
if ($entity->hook('beforeRestore') === false) {
145+
return;
146+
}
147+
148+
$entity->saveAndUnload(['is_deleted' => false]);
149+
150+
$entity->hook('afterRestore');
151+
});
152+
}
153+
}
154+
74155
class RandomTest extends TestCase
75156
{
76157
public function testRate(): void
@@ -87,6 +168,46 @@ public function testRate(): void
87168
self::assertSame(2, $m->executeCountQuery());
88169
}
89170

171+
public function testSoftDelete(): void
172+
{
173+
$m = new Model_Item($this->db);
174+
$this->createMigrator($m)->dropIfExists()->create();
175+
176+
$m->insert(['name' => 'John']);
177+
$m->insert(['name' => 'Michael']);
178+
179+
$softDeleteController = new ControllerSoftDelete();
180+
181+
$entity = $m->loadBy('name', 'Michael');
182+
$softDeleteController->softDelete($entity);
183+
static::assertSame([
184+
'item' => [
185+
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => null, 'is_deleted' => '0'],
186+
2 => ['id' => 2, 'name' => 'Michael', 'parent_item_id' => null, 'is_deleted' => '1'],
187+
],
188+
], $this->getDb());
189+
190+
$entity = $softDeleteController->invokeCallbackWithoutUndeletedCondition($m, function () use ($m) {
191+
return $m->loadBy('name', 'Michael');
192+
});
193+
$softDeleteController->restore($entity);
194+
static::assertSame([
195+
'item' => [
196+
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => null, 'is_deleted' => '0'],
197+
2 => ['id' => 2, 'name' => 'Michael', 'parent_item_id' => null, 'is_deleted' => '0'],
198+
],
199+
], $this->getDb());
200+
201+
$entity = $m->loadBy('name', 'Michael');
202+
$entity->delete();
203+
static::assertSame([
204+
'item' => [
205+
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => null, 'is_deleted' => '0'],
206+
2 => ['id' => 2, 'name' => 'Michael', 'parent_item_id' => null, 'is_deleted' => '1'],
207+
],
208+
], $this->getDb());
209+
}
210+
90211
public function testTitleImport(): void
91212
{
92213
$this->setDb([
@@ -205,16 +326,16 @@ public function testSameTable(): void
205326
{
206327
$this->setDb([
207328
'item' => [
208-
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => 1],
209-
['id' => 2, 'name' => 'Sue', 'parent_item_id' => 1],
210-
['id' => 3, 'name' => 'Smith', 'parent_item_id' => 2],
329+
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => 1, 'is_deleted' => false],
330+
['id' => 2, 'name' => 'Sue', 'parent_item_id' => 1, 'is_deleted' => false],
331+
['id' => 3, 'name' => 'Smith', 'parent_item_id' => 2, 'is_deleted' => false],
211332
],
212333
]);
213334

214335
$m = new Model_Item($this->db, ['table' => 'item']);
215336

216337
self::assertSame(
217-
['id' => 3, 'name' => 'Smith', 'parent_item_id' => 2, 'parent_item' => 'Sue'],
338+
['id' => 3, 'name' => 'Smith', 'parent_item_id' => 2, 'parent_item' => 'Sue', 'is_deleted' => false],
218339
$m->load(3)->get()
219340
);
220341
}
@@ -350,8 +471,8 @@ public function testGetTitle(): void
350471
{
351472
$this->setDb([
352473
'item' => [
353-
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => 1],
354-
['id' => 2, 'name' => 'Sue', 'parent_item_id' => 1],
474+
1 => ['id' => 1, 'name' => 'John', 'parent_item_id' => 1, 'is_deleted' => false],
475+
['id' => 2, 'name' => 'Sue', 'parent_item_id' => 1, 'is_deleted' => false],
355476
],
356477
]);
357478

0 commit comments

Comments
 (0)