Completed
Push — master ( 72048b...aafbe4 )
by Peter
18:50
created

EntityManager::beforeValidate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package   maslosoft/mangan
7
 * @licence   AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link      https://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan;
15
16
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
17
use Maslosoft\Mangan\Events\Event;
18
use Maslosoft\Mangan\Events\ModelEvent;
19
use Maslosoft\Mangan\Exceptions\BadAttributeException;
20
use Maslosoft\Mangan\Exceptions\ManganException;
21
use Maslosoft\Mangan\Helpers\CollectionNamer;
22
use Maslosoft\Mangan\Helpers\PkManager;
23
use Maslosoft\Mangan\Interfaces\CriteriaInterface;
24
use Maslosoft\Mangan\Interfaces\EntityManagerInterface;
25
use Maslosoft\Mangan\Interfaces\ScenariosInterface;
26
use Maslosoft\Mangan\Meta\ManganMeta;
27
use Maslosoft\Mangan\Options\EntityOptions;
28
use Maslosoft\Mangan\Signals\AfterDelete;
29
use Maslosoft\Mangan\Signals\AfterSave;
30
use Maslosoft\Mangan\Signals\BeforeDelete;
31
use Maslosoft\Mangan\Signals\BeforeSave;
32
use Maslosoft\Mangan\Transformers\RawArray;
33
use Maslosoft\Mangan\Transformers\SafeArray;
34
use Maslosoft\Signals\Signal;
35
use MongoCollection;
36
37
/**
38
 * EntityManager
39
 *
40
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
41
 */
42
class EntityManager implements EntityManagerInterface
43
{
44
45
	/**
46
	 * Model
47
	 * @var AnnotatedInterface
48
	 */
49
	public $model = null;
50
51
	/**
52
	 *
53
	 * @var ScopeManager
54
	 */
55
	private $sm = null;
56
57
	/**
58
	 *
59
	 * @var
60
	 */
61
	public $meta = null;
62
63
	/**
64
	 * Options
65
	 * @var EntityOptions
66
	 */
67
	public $options = null;
68
69
	/**
70
	 * Current collection name
71
	 * @var string
72
	 */
73
	public $collectionName = '';
74
75
	/**
76
	 * Validator instance
77
	 * @var Validator
78
	 */
79
	private $validator = null;
80
81
	/**
82
	 * Current collection
83
	 * @var MongoCollection
84
	 */
85
	private $_collection = null;
86
87
	/**
88
	 * Result of last operation
89
	 * @var bool|array
90
	 */
91
	private $lastResult = [];
92
93
	/**
94
	 * Create entity manager
95
	 * @param AnnotatedInterface $model
96
	 * @param Mangan             $mangan
97
	 * @throws ManganException
98
	 */
99 122
	public function __construct(AnnotatedInterface $model, Mangan $mangan = null)
100
	{
101 122
		$this->model = $model;
102 122
		$this->sm = new ScopeManager($model);
103 122
		$this->options = new EntityOptions($model);
104 122
		$this->collectionName = CollectionNamer::nameCollection($model);
105 122
		$this->meta = ManganMeta::create($model);
106 122
		$this->validator = new Validator($model);
107 122
		if (null === $mangan)
108
		{
109 119
			$mangan = Mangan::fromModel($model);
110
		}
111 122
		if (!$this->collectionName)
112
		{
113
			throw new ManganException(sprintf('Invalid collection name for model: `%s`', $this->meta->type()->name));
114
		}
115 122
		$this->_collection = new MongoCollection($mangan->getDbInstance(), $this->collectionName);
116 122
	}
117
118
	/**
119
	 * Create model related entity manager.
120
	 * This will create customized entity manger if defined in model with EntityManager annotation.
121
	 * If no custom entity manager is defined this will return default EntityManager.
122
	 * @param AnnotatedInterface $model
123
	 * @param Mangan             $mangan
124
	 * @return EntityManagerInterface
125
	 */
126 113
	public static function create($model, Mangan $mangan = null)
127
	{
128 113
		$emClass = ManganMeta::create($model)->type()->entityManager ?: static::class;
129 113
		return new $emClass($model, $mangan);
130
	}
131
132
	/**
133
	 * Set attributes en masse.
134
	 * Attributes will be filtered according to SafeAnnotation.
135
	 * Only attributes marked as safe will be set, other will be ignored.
136
	 *
137
	 * @param mixed[] $attributes
138
	 */
139
	public function setAttributes($attributes)
140
	{
141
		SafeArray::toModel($attributes, $this->model, $this->model);
142
	}
143
144
	/**
145
	 * Inserts a row into the table based on this active record attributes.
146
	 * If the table's primary key is auto-incremental and is null before insertion,
147
	 * it will be populated with the actual value after insertion.
148
	 *
149
	 * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
150
	 * After the record is inserted to DB successfully, its {@link isNewRecord} property will be set false,
151
	 * and its {@link scenario} property will be set to be 'update'.
152
	 *
153
	 * @param AnnotatedInterface $model if want to insert different model than set in constructor
154
	 *
155
	 * @return boolean whether the attributes are valid and the record is inserted successfully.
156
	 * @throws ManganException if the record is not new
157
	 * @throws ManganException on fail of insert or insert of empty document
158
	 * @throws ManganException on fail of insert, when safe flag is set to true
159
	 * @throws ManganException on timeout of db operation , when safe flag is set to true
160
	 */
161 36
	public function insert(AnnotatedInterface $model = null)
162
	{
163 36
		$model = $model ?: $this->model;
164 36
		if ($this->beforeSave($model, EntityManagerInterface::EventBeforeInsert))
165
		{
166 36
			$rawData = RawArray::fromModel($model);
167
168 36
			$opts = $this->options->getSaveOptions();
169 36
			$rawResult = $this->_collection->insert($rawData, $opts);
170 36
			$result = $this->insertResult($rawResult);
171
172 36
			if ($result)
173
			{
174 36
				$this->afterSave($model, EntityManagerInterface::EventAfterInsert);
175 36
				return true;
176
			}
177
			throw new ManganException('Can\t save the document to disk, or attempting to save an empty document. ' . ucfirst($rawResult['errmsg']));
178
		}
179
		AspectManager::removeAspect($model, self::AspectSaving);
180
		return false;
181
	}
182
183
	/**
184
	 * Updates the row represented by this active document.
185
	 * All loaded attributes will be saved to the database.
186
	 * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
187
	 *
188
	 * @param array $attributes list of attributes that need to be saved. Defaults to null,
189
	 *                          meaning all attributes that are loaded from DB will be saved.
190
	 * @return boolean whether the update is successful
191
	 * @throws ManganException if the record is new
192
	 * @throws ManganException on fail of update
193
	 * @throws ManganException on timeout of db operation , when safe flag is set to true
194
	 */
195 6
	public function update(array $attributes = null)
196
	{
197 6
		if ($this->beforeSave($this->model, EntityManagerInterface::EventBeforeUpdate))
198
		{
199 6
			$criteria = PkManager::prepareFromModel($this->model);
200 6
			$result = $this->updateOne($criteria, $attributes);
201 5
			if ($result)
202
			{
203 5
				$this->afterSave($this->model, EntityManagerInterface::EventAfterUpdate);
204 5
				return true;
205
			}
206
			throw new ManganException('Can\t save the document to disk, or attempting to save an empty document.');
207
		}
208
		AspectManager::removeAspect($this->model, self::AspectSaving);
209
		return false;
210
	}
211
212
	/**
213
	 * Updates one document with the specified criteria and attributes
214
	 *
215
	 * This is more *raw* update:
216
	 *
217
	 * * Does not raise any events or signals
218
	 * * Does not perform any validation
219
	 *
220
	 * @param array|CriteriaInterface $criteria   query criteria.
221
	 * @param array                   $attributes list of attributes that need to be saved. Defaults to null,
222
	 * @param bool Whether tu force update/upsert document
223
	 *                                            meaning all attributes that are loaded from DB will be saved.
224
	 * @return bool
225
	 */
226 85
	public function updateOne($criteria = null, array $attributes = null, $modify = false)
227
	{
228 85
		$criteria = $this->sm->apply($criteria);
229 85
		$rawData = RawArray::fromModel($this->model, $attributes);
0 ignored issues
show
Documentation introduced by
$attributes is of type null|array, but the function expects a array<integer,string>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
230
231
		// filter attributes if set in param
232 85
		if ($attributes !== null)
233
		{
234 3
			$meta = ManganMeta::create($this->model);
235 3
			foreach ($attributes as $key)
236
			{
237 3
				if ($meta->$key === false)
238
				{
239 3
					throw new BadAttributeException(sprintf("Unknown attribute `%s` on model `%s`", $key, get_class($this->model)));
240
				}
241
			}
242 2
			$modify = true;
243 2
			foreach ($rawData as $key => $value)
244
			{
245 2
				if (!in_array($key, $attributes))
246
				{
247 2
					unset($rawData[$key]);
248
				}
249
			}
250
		}
251
		else
252
		{
253 85
			$fields = array_keys(ManganMeta::create($this->model)->fields());
254 85
			$setFields = array_keys($rawData);
255 85
			$diff = array_diff($fields, $setFields);
256
257 85
			if (!empty($diff))
258
			{
259 6
				$modify = true;
260
			}
261
		}
262 85
		if ($modify)
263
		{
264
			// Id could be altered, so skip it as it cannot be changed
265 8
			unset($rawData['_id']);
266 8
			$data = ['$set' => $rawData];
267
		}
268
		else
269
		{
270 82
			$data = $rawData;
271
		}
272 85
		$conditions = $criteria->getConditions();
273 85
		$opts = $this->options->getSaveOptions(['multiple' => false, 'upsert' => true]);
274 85
		$collection = $this->getCollection();
275
276 85
		$result = $collection->update($conditions, $data, $opts);
277 85
		return $this->updateResult($result);
278
	}
279
280
	/**
281
	 * Atomic, in-place update method.
282
	 *
283
	 * @param Modifier          $modifier updating rules to apply
284
	 * @param CriteriaInterface $criteria condition to limit updating rules
285
	 * @return boolean
286
	 */
287 1
	public function updateAll(Modifier $modifier, CriteriaInterface $criteria = null)
288
	{
289 1
		if ($modifier->canApply())
290
		{
291 1
			$criteria = $this->sm->apply($criteria);
292 1
			$conditions = $criteria->getConditions();
293 1
			$mods = $modifier->getModifiers();
294 1
			$opts = $this->options->getSaveOptions([
295 1
				'upsert' => false,
296
				'multiple' => true
297
			]);
298 1
			$result = $this->getCollection()->update($conditions, $mods, $opts);
299 1
			return $this->updateResult($result);
300
		}
301
		else
302
		{
303
			return false;
304
		}
305
	}
306
307
	/**
308
	 * Replaces the current document.
309
	 *
310
	 * **NOTE: This will overwrite entire document.**
311
	 * Any filtered out properties will be removed as well.
312
	 *
313
	 * The record is inserted as a document into the database collection, if exists it will be replaced.
314
	 *
315
	 * Validation will be performed before saving the record. If the validation fails,
316
	 * the record will not be saved. You can call {@link getErrors()} to retrieve the
317
	 * validation errors.
318
	 *
319
	 * @param boolean $runValidation whether to perform validation before saving the record.
320
	 *                               If the validation fails, the record will not be saved to database.
321
	 *
322
	 * @return boolean whether the saving succeeds
323
	 */
324
	public function replace($runValidation = true)
325
	{
326
		$this->beforeValidate($this->model);
327
		if (!$runValidation || $this->validator->validate())
328
		{
329
			$model = $this->model;
330
			if ($this->beforeSave($model))
331
			{
332
				$data = RawArray::fromModel($model);
333
				$rawResult = $this->_collection->save($data, $this->options->getSaveOptions());
334
				$result = $this->insertResult($rawResult);
335
336
				if ($result)
337
				{
338
					$this->afterSave($model);
339
					return true;
340
				}
341
				$msg = '';
342
				if (!empty($rawResult['errmsg']))
343
				{
344
					$msg = $rawResult['errmsg'];
345
				}
346
				throw new ManganException("Can't save the document to disk, or attempting to save an empty document. $msg");
347
			}
348
			AspectManager::removeAspect($model, self::AspectSaving);
349
			return false;
350
		}
351
		else
352
		{
353
			AspectManager::removeAspect($this->model, self::AspectSaving);
354
			return false;
355
		}
356
	}
357
358
	/**
359
	 * Saves the current document.
360
	 *
361
	 * The record is inserted as a document into the database collection or updated if exists.
362
	 *
363
	 * Filtered out properties will remain in database - it is partial safe.
364
	 *
365
	 * Validation will be performed before saving the record. If the validation fails,
366
	 * the record will not be saved. You can call {@link getErrors()} to retrieve the
367
	 * validation errors.
368
	 *
369
	 * @param boolean $runValidation whether to perform validation before saving the record.
370
	 *                               If the validation fails, the record will not be saved to database.
371
	 *
372
	 * @return boolean whether the saving succeeds
373
	 */
374 82
	public function save($runValidation = true)
375
	{
376 82
		return $this->upsert($runValidation);
377
	}
378
379
	/**
380
	 * Updates or inserts the current document. This will try to update existing fields.
381
	 * Will keep already stored data if present in document.
382
	 *
383
	 * If document does not exist, a new one will be inserted.
384
	 *
385
	 * @param boolean $runValidation
386
	 * @return boolean
387
	 * @throws ManganException
388
	 */
389 86
	public function upsert($runValidation = true)
390
	{
391 86
		$this->beforeValidate($this->model);
392 86
		if (!$runValidation || $this->validator->validate())
393
		{
394 86
			$model = $this->model;
395 86
			if ($this->beforeSave($model))
396
			{
397 83
				$criteria = PkManager::prepareFromModel($this->model);
398 83
				foreach ($criteria->getConditions() as $field => $value)
399
				{
400 83
					if (empty($this->model->$field))
401
					{
402 83
						$this->model->$field = $value;
403
					}
404
				}
405 83
				$result = $this->updateOne($criteria);
406
407 83
				if ($result)
408
				{
409 83
					$this->afterSave($model);
410 83
					return true;
411
				}
412
				$errmsg = '';
413
				if (!empty($this->lastResult['errmsg']))
414
				{
415
					$errmsg = ucfirst($this->lastResult['errmsg']) . '.';
416
				}
417
				throw new ManganException("Can't save the document to disk, or attempting to save an empty document. $errmsg");
418
			}
419 3
			AspectManager::removeAspect($this->model, self::AspectSaving);
420 3
			return false;
421
		}
422
		else
423
		{
424 3
			AspectManager::removeAspect($this->model, self::AspectSaving);
425 3
			return false;
426
		}
427
	}
428
429
	/**
430
	 * Reloads document from database.
431
	 * It return true if document is reloaded and false if it's no longer exists.
432
	 *
433
	 * @return boolean
434
	 */
435 2
	public function refresh()
436
	{
437 2
		$conditions = PkManager::prepareFromModel($this->model)->getConditions();
438 2
		$data = $this->getCollection()->findOne($conditions);
439 2
		if (null !== $data)
440
		{
441 2
			RawArray::toModel($data, $this->model, $this->model);
442 2
			return true;
443
		}
444
		else
445
		{
446 2
			return false;
447
		}
448
	}
449
450
	/**
451
	 * Deletes the document from database.
452
	 * @return boolean whether the deletion is successful.
453
	 */
454 10
	public function delete()
455
	{
456 10
		if ($this->beforeDelete())
457
		{
458 9
			$conditions = PkManager::prepareFromModel($this->model);
459 9
			$result = $this->deleteOne($conditions);
460
461 9
			if ($result !== false)
462
			{
463 9
				$this->afterDelete();
464 9
				return true;
465
			}
466
			else
467
			{
468 1
				return false;
469
			}
470
		}
471
		else
472
		{
473 1
			return false;
474
		}
475
	}
476
477
	/**
478
	 * Deletes one document with the specified primary keys.
479
	 * <b>Does not raise beforeDelete</b>
480
	 * See {@link find()} for detailed explanation about $condition and $params.
481
	 * @param array|CriteriaInterface $criteria query criteria.
482
	 * @return bool
483
	 */
484 11
	public function deleteOne($criteria = null)
485
	{
486 11
		$criteria = $this->sm->apply($criteria);
487
488 11
		$result = $this->getCollection()->remove($criteria->getConditions(), $this->options->getSaveOptions([
489 11
			'justOne' => true
490
		]));
491 11
		return $this->deleteResult($result);
492
	}
493
494
	/**
495
	 * Deletes document with the specified primary key.
496
	 * See {@link find()} for detailed explanation about $condition and $params.
497
	 * @param mixed                   $pkValue  primary key value(s). Use array for multiple primary keys. For
498
	 *                                          composite key, each key value must be an array (column name=>column
499
	 *                                          value).
500
	 * @param array|CriteriaInterface $criteria query criteria.
501
	 *
502
	 * @return bool
503
	 */
504 3
	public function deleteByPk($pkValue, $criteria = null)
505
	{
506 3
		if ($this->beforeDelete())
507
		{
508 2
			$criteria = $this->sm->apply($criteria);
509 2
			$criteria->mergeWith(PkManager::prepare($this->model, $pkValue));
510
511 2
			$result = $this->getCollection()->remove($criteria->getConditions(), $this->options->getSaveOptions([
512 2
				'justOne' => true
513
			]));
514 2
			return $this->deleteResult($result);
515
		}
516 1
		return false;
517
	}
518
519
	/**
520
	 * Deletes documents with the specified primary keys.
521
	 * See {@link find()} for detailed explanation about $condition and $params.
522
	 * @param mixed[]                 $pkValues Primary keys array
523
	 * @param array|CriteriaInterface $criteria query criteria.
524
	 * @return bool
525
	 */
526 3
	public function deleteAllByPk($pkValues, $criteria = null)
527
	{
528 3
		if ($this->beforeDelete())
529
		{
530 2
			$criteria = $this->sm->apply($criteria);
531 2
			$criteria->mergeWith(PkManager::prepareAll($this->model, $pkValues, $criteria));
0 ignored issues
show
Bug introduced by
It seems like \Maslosoft\Mangan\Helper..., $pkValues, $criteria) can be null; however, mergeWith() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
532 2
			$conditions = $criteria->getConditions();
533 2
			$opts = $this->options->getSaveOptions([
534 2
				'justOne' => false
535
			]);
536 2
			$result = $this->getCollection()->remove($conditions, $opts);
537 2
			return $this->deleteResult($result);
538
		}
539 1
		return false;
540
	}
541
542
	/**
543
	 * Deletes documents with the specified primary keys.
544
	 *
545
	 * **Does not raise beforeDelete event and does not emit signals**
546
	 *
547
	 * See {@link find()} for detailed explanation about $condition and $params.
548
	 *
549
	 * @param array|CriteriaInterface $criteria query criteria.
550
	 * @return bool
551
	 */
552 5
	public function deleteAll($criteria = null)
553
	{
554 5
		$criteria = $this->sm->apply($criteria);
555
556 5
		$conditions = $criteria->getConditions();
557
558
		// NOTE: Do not use [justOne => false] here
559 5
		$opts = $this->options->getSaveOptions();
560 5
		$result = $this->getCollection()->remove($conditions, $opts);
561 5
		return $this->deleteResult($result);
562
	}
563
564 117
	public function getCollection()
565
	{
566 117
		return $this->_collection;
567
	}
568
569
	/**
570
	 * Make status uniform
571
	 * @param bool|array $result
572
	 * @return bool Return true if succeed
573
	 */
574 19
	private function deleteResult($result)
575
	{
576 19
		$this->lastResult = $result;
577 19
		if (is_array($result))
578
		{
579 19
			return $result['n'] > 0;
580
		}
581
		return $result;
582
	}
583
584
	/**
585
	 * Make status uniform
586
	 * @param bool|array $result
587
	 * @return bool Return true if succeed
588
	 */
589 36
	private function insertResult($result)
590
	{
591 36
		$this->lastResult = $result;
592 36
		if (is_array($result))
593
		{
594 36
			return $result['ok'] > 0;
595
		}
596
		return $result;
597
	}
598
599
	/**
600
	 * Make status uniform
601
	 * @param bool|array $result
602
	 * @return bool Return true if succeed
603
	 */
604 85
	private function updateResult($result)
605
	{
606 85
		$this->lastResult = $result;
607 85
		if (is_array($result))
608
		{
609 85
			return $result['ok'] > 0;
610
		}
611
		return $result;
612
	}
613
614
// <editor-fold defaultstate="collapsed" desc="Event and Signal handling">
615
616 86
	private function beforeValidate($model)
617
	{
618 86
		AspectManager::addAspect($model, self::AspectSaving);
619 86
	}
620
621
	/**
622
	 * Take care of EventBeforeSave
623
	 * @see EventBeforeSave
624
	 * @param                 $model
625
	 * @param string $event
626
	 * @return boolean
627
	 */
628 118
	private function beforeSave($model, $event = null)
629
	{
630 118
		AspectManager::addAspect($model, self::AspectSaving);
631 118
		$result = Event::Valid($model, EntityManagerInterface::EventBeforeSave);
632 118
		if ($result)
633
		{
634 115
			if (!empty($event))
635
			{
636 42
				Event::trigger($model, $event);
637
			}
638 115
			(new Signal)->emit(new BeforeSave($model));
639
		}
640 118
		return $result;
641
	}
642
643
	/**
644
	 * Take care of EventAfterSave
645
	 * @see EventAfterSave
646
	 * @param                 $model
647
	 * @param null|ModelEvent $event
648
	 */
649 115
	private function afterSave($model, $event = null)
650
	{
651 115
		Event::trigger($model, EntityManagerInterface::EventAfterSave);
652 115
		if (!empty($event))
653
		{
654 41
			Event::trigger($model, $event);
0 ignored issues
show
Documentation introduced by
$event is of type object<Maslosoft\Mangan\Events\ModelEvent>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
655
		}
656 115
		(new Signal)->emit(new AfterSave($model));
657 115
		ScenarioManager::setScenario($model, ScenariosInterface::Update);
658 115
		AspectManager::removeAspect($model, self::AspectSaving);
659 115
	}
660
661
	/**
662
	 * This method is invoked before deleting a record.
663
	 * The default implementation raises the {@link onBeforeDelete} event.
664
	 * You may override this method to do any preparation work for record deletion.
665
	 * Make sure you call the parent implementation so that the event is raised properly.
666
	 * @return boolean whether the record should be deleted. Defaults to true.
667
	 */
668 14
	private function beforeDelete()
669
	{
670 14
		AspectManager::addAspect($this->model, self::AspectRemoving);
671 14
		$result = Event::valid($this->model, EntityManagerInterface::EventBeforeDelete);
672 14
		if ($result)
673
		{
674 13
			(new Signal)->emit(new BeforeDelete($this->model));
675 13
			ScenarioManager::setScenario($this->model, ScenariosInterface::Delete);
676
		}
677 14
		return $result;
678
	}
679
680
	/**
681
	 * This method is invoked after deleting a record.
682
	 * The default implementation raises the {@link onAfterDelete} event.
683
	 * You may override this method to do postprocessing after the record is deleted.
684
	 * Make sure you call the parent implementation so that the event is raised properly.
685
	 */
686 9
	private function afterDelete()
687
	{
688 9
		$event = new ModelEvent($this->model);
689 9
		Event::trigger($this->model, EntityManagerInterface::EventAfterDelete, $event);
690 9
		(new Signal)->emit(new AfterDelete($this->model));
691 9
		AspectManager::removeAspect($this->model, self::AspectRemoving);
692 9
	}
693
694
// </editor-fold>
695
}
696