Completed
Push — mongo-adapter ( 574367 )
by Peter
23:25
created

EntityManager::afterSave()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
nc 2
cc 2
nop 2
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 array
90
	 */
91
	private $lastResult = [];
92
93
	/**
94
	 * Create entity manager
95
	 * @param AnnotatedInterface $model
96
	 * @param Mangan             $mangan
97
	 * @throws ManganException
98
	 */
99
	public function __construct(AnnotatedInterface $model, Mangan $mangan = null)
100
	{
101
		$this->model = $model;
102
		$this->sm = new ScopeManager($model);
103
		$this->options = new EntityOptions($model);
104
		$this->collectionName = CollectionNamer::nameCollection($model);
105
		$this->meta = ManganMeta::create($model);
106
		$this->validator = new Validator($model);
107
		if (null === $mangan)
108
		{
109
			$mangan = Mangan::fromModel($model);
110
		}
111
		if (!$this->collectionName)
112
		{
113
			throw new ManganException(sprintf('Invalid collection name for model: `%s`', $this->meta->type()->name));
114
		}
115
		$this->_collection = new MongoCollection($mangan->getDbInstance(), $this->collectionName);
116
	}
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
	public static function create($model, Mangan $mangan = null)
127
	{
128
		$emClass = ManganMeta::create($model)->type()->entityManager ?: static::class;
129
		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
	public function insert(AnnotatedInterface $model = null)
162
	{
163
		$model = $model ?: $this->model;
164
		if ($this->beforeSave($model, EntityManagerInterface::EventBeforeInsert))
165
		{
166
			$rawData = RawArray::fromModel($model);
167
168
			$opts = $this->options->getSaveOptions();
169
			$rawResult = $this->_collection->insert($rawData, $opts);
170
			$result = $this->insertResult($rawResult);
171
172
			if ($result)
173
			{
174
				$this->afterSave($model, EntityManagerInterface::EventAfterInsert);
175
				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
	public function update(array $attributes = null)
196
	{
197
		if ($this->beforeSave($this->model, EntityManagerInterface::EventBeforeUpdate))
198
		{
199
			$criteria = PkManager::prepareFromModel($this->model);
200
			$result = $this->updateOne($criteria, $attributes);
201
			if ($result)
202
			{
203
				$this->afterSave($this->model, EntityManagerInterface::EventAfterUpdate);
204
				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
	public function updateOne($criteria = null, array $attributes = null, $modify = false)
227
	{
228
		$criteria = $this->sm->apply($criteria);
229
		$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
		if ($attributes !== null)
233
		{
234
			$meta = ManganMeta::create($this->model);
235
			foreach ($attributes as $key)
236
			{
237
				if ($meta->$key === false)
238
				{
239
					throw new BadAttributeException(sprintf("Unknown attribute `%s` on model `%s`", $key, get_class($this->model)));
240
				}
241
			}
242
			$modify = true;
243
			foreach ($rawData as $key => $value)
244
			{
245
				if (!in_array($key, $attributes))
246
				{
247
					unset($rawData[$key]);
248
				}
249
			}
250
		}
251
		else
252
		{
253
			$fields = array_keys(ManganMeta::create($this->model)->fields());
254
			$setFields = array_keys($rawData);
255
			$diff = array_diff($fields, $setFields);
256
257
			if (!empty($diff))
258
			{
259
				$modify = true;
260
			}
261
		}
262
		if ($modify)
263
		{
264
			// Id could be altered, so skip it as it cannot be changed
265
			unset($rawData['_id']);
266
			$data = ['$set' => $rawData];
267
		}
268
		else
269
		{
270
			$data = $rawData;
271
		}
272
		$conditions = $criteria->getConditions();
273
		$opts = $this->options->getSaveOptions(['multiple' => false, 'upsert' => true]);
274
		$collection = $this->getCollection();
275
276
		$result = $collection->update($conditions, $data, $opts);
277
		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
	public function updateAll(Modifier $modifier, CriteriaInterface $criteria = null)
288
	{
289
		if ($modifier->canApply())
290
		{
291
			$criteria = $this->sm->apply($criteria);
292
			$conditions = $criteria->getConditions();
293
			$mods = $modifier->getModifiers();
294
			$opts = $this->options->getSaveOptions([
295
				'upsert' => false,
296
				'multiple' => true
297
			]);
298
			$result = $this->getCollection()->update($conditions, $mods, $opts);
299
			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
		if (!$runValidation || $this->validator->validate())
327
		{
328
			$model = $this->model;
329
			if ($this->beforeSave($model))
330
			{
331
				$data = RawArray::fromModel($model);
332
				$rawResult = $this->_collection->save($data, $this->options->getSaveOptions());
333
				$result = $this->insertResult($rawResult);
334
335
				if ($result)
336
				{
337
					$this->afterSave($model);
338
					return true;
339
				}
340
				$msg = '';
341
				if (!empty($rawResult['errmsg']))
342
				{
343
					$msg = $rawResult['errmsg'];
344
				}
345
				throw new ManganException("Can't save the document to disk, or attempting to save an empty document. $msg");
346
			}
347
			AspectManager::removeAspect($model, self::AspectSaving);
348
			return false;
349
		}
350
		else
351
		{
352
			AspectManager::removeAspect($this->model, self::AspectSaving);
353
			return false;
354
		}
355
	}
356
357
	/**
358
	 * Saves the current document.
359
	 *
360
	 * The record is inserted as a document into the database collection or updated if exists.
361
	 *
362
	 * Filtered out properties will remain in database - it is partial safe.
363
	 *
364
	 * Validation will be performed before saving the record. If the validation fails,
365
	 * the record will not be saved. You can call {@link getErrors()} to retrieve the
366
	 * validation errors.
367
	 *
368
	 * @param boolean $runValidation whether to perform validation before saving the record.
369
	 *                               If the validation fails, the record will not be saved to database.
370
	 *
371
	 * @return boolean whether the saving succeeds
372
	 */
373
	public function save($runValidation = true)
374
	{
375
		return $this->upsert($runValidation);
376
	}
377
378
	/**
379
	 * Updates or inserts the current document. This will try to update existing fields.
380
	 * Will keep already stored data if present in document.
381
	 *
382
	 * If document does not exist, a new one will be inserted.
383
	 *
384
	 * @param boolean $runValidation
385
	 * @return boolean
386
	 * @throws ManganException
387
	 */
388
	public function upsert($runValidation = true)
389
	{
390
		if (!$runValidation || $this->validator->validate())
391
		{
392
			$model = $this->model;
393
			if ($this->beforeSave($model))
394
			{
395
				$criteria = PkManager::prepareFromModel($this->model);
396
				foreach ($criteria->getConditions() as $field => $value)
397
				{
398
					if (empty($this->model->$field))
399
					{
400
						$this->model->$field = $value;
401
					}
402
				}
403
				$result = $this->updateOne($criteria);
404
405
				if ($result)
406
				{
407
					$this->afterSave($model);
408
					return true;
409
				}
410
				$errmsg = '';
411
				if (!empty($this->lastResult['errmsg']))
412
				{
413
					$errmsg = ucfirst($this->lastResult['errmsg']) . '.';
414
				}
415
				throw new ManganException("Can't save the document to disk, or attempting to save an empty document. $errmsg");
416
			}
417
			AspectManager::removeAspect($this->model, self::AspectSaving);
418
			return false;
419
		}
420
		else
421
		{
422
			AspectManager::removeAspect($this->model, self::AspectSaving);
423
			return false;
424
		}
425
	}
426
427
	/**
428
	 * Reloads document from database.
429
	 * It return true if document is reloaded and false if it's no longer exists.
430
	 *
431
	 * @return boolean
432
	 */
433
	public function refresh()
434
	{
435
		$conditions = PkManager::prepareFromModel($this->model)->getConditions();
436
		$data = $this->getCollection()->findOne($conditions);
437
		if (null !== $data)
438
		{
439
			RawArray::toModel($data, $this->model, $this->model);
440
			return true;
441
		}
442
		else
443
		{
444
			return false;
445
		}
446
	}
447
448
	/**
449
	 * Deletes the document from database.
450
	 * @return boolean whether the deletion is successful.
451
	 */
452
	public function delete()
453
	{
454
		if ($this->beforeDelete())
455
		{
456
			$conditions = PkManager::prepareFromModel($this->model);
457
			$result = $this->deleteOne($conditions);
458
459
			if ($result !== false)
460
			{
461
				$this->afterDelete();
462
				return true;
463
			}
464
			else
465
			{
466
				return false;
467
			}
468
		}
469
		else
470
		{
471
			return false;
472
		}
473
	}
474
475
	/**
476
	 * Deletes one document with the specified primary keys.
477
	 * <b>Does not raise beforeDelete</b>
478
	 * See {@link find()} for detailed explanation about $condition and $params.
479
	 * @param array|CriteriaInterface $criteria query criteria.
480
	 * @return bool
481
	 */
482
	public function deleteOne($criteria = null)
483
	{
484
		$criteria = $this->sm->apply($criteria);
485
486
		$result = $this->getCollection()->remove($criteria->getConditions(), $this->options->getSaveOptions([
487
			'justOne' => true
488
		]));
489
		return $this->deleteResult($result);
490
	}
491
492
	/**
493
	 * Deletes document with the specified primary key.
494
	 * See {@link find()} for detailed explanation about $condition and $params.
495
	 * @param mixed                   $pkValue  primary key value(s). Use array for multiple primary keys. For
496
	 *                                          composite key, each key value must be an array (column name=>column
497
	 *                                          value).
498
	 * @param array|CriteriaInterface $criteria query criteria.
499
	 *
500
	 * @return bool
501
	 */
502
	public function deleteByPk($pkValue, $criteria = null)
503
	{
504
		if ($this->beforeDelete())
505
		{
506
			$criteria = $this->sm->apply($criteria);
507
			$criteria->mergeWith(PkManager::prepare($this->model, $pkValue));
508
509
			$result = $this->getCollection()->remove($criteria->getConditions(), $this->options->getSaveOptions([
510
				'justOne' => true
511
			]));
512
			return $this->deleteResult($result);
513
		}
514
		return false;
515
	}
516
517
	/**
518
	 * Deletes documents with the specified primary keys.
519
	 * See {@link find()} for detailed explanation about $condition and $params.
520
	 * @param mixed[]                 $pkValues Primary keys array
521
	 * @param array|CriteriaInterface $criteria query criteria.
522
	 * @return bool
523
	 */
524
	public function deleteAllByPk($pkValues, $criteria = null)
525
	{
526
		if ($this->beforeDelete())
527
		{
528
			$criteria = $this->sm->apply($criteria);
529
			$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...
530
			$conditions = $criteria->getConditions();
531
			$opts = $this->options->getSaveOptions([
532
				'justOne' => false
533
			]);
534
			$result = $this->getCollection()->remove($conditions, $opts);
535
			return $this->deleteResult($result);
536
		}
537
		return false;
538
	}
539
540
	/**
541
	 * Deletes documents with the specified primary keys.
542
	 *
543
	 * **Does not raise beforeDelete event and does not emit signals**
544
	 *
545
	 * See {@link find()} for detailed explanation about $condition and $params.
546
	 *
547
	 * @param array|CriteriaInterface $criteria query criteria.
548
	 * @return bool
549
	 */
550
	public function deleteAll($criteria = null)
551
	{
552
		$criteria = $this->sm->apply($criteria);
553
554
		$conditions = $criteria->getConditions();
555
556
		// NOTE: Do not use [justOne => false] here
557
		$opts = $this->options->getSaveOptions();
558
		$result = $this->getCollection()->remove($conditions, $opts);
559
		return $this->deleteResult($result);
560
	}
561
562
	public function getCollection()
563
	{
564
		return $this->_collection;
565
	}
566
567
	/**
568
	 * Make status uniform
569
	 * @param bool|array $result
570
	 * @return bool Return true if succeed
571
	 */
572
	private function deleteResult($result)
573
	{
574
		$this->lastResult = $result;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result can also be of type boolean. However, the property $lastResult is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
575
		if (is_array($result))
576
		{
577
			return $result['n'] > 0;
578
		}
579
		return $result;
580
	}
581
582
	/**
583
	 * Make status uniform
584
	 * @param bool|array $result
585
	 * @return bool Return true if succeed
586
	 */
587
	private function insertResult($result)
588
	{
589
		$this->lastResult = $result;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result can also be of type boolean. However, the property $lastResult is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
590
		if (is_array($result))
591
		{
592
			return $result['ok'] > 0;
593
		}
594
		return $result;
595
	}
596
597
	/**
598
	 * Make status uniform
599
	 * @param bool|array $result
600
	 * @return bool Return true if succeed
601
	 */
602
	private function updateResult($result)
603
	{
604
		$this->lastResult = $result;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result can also be of type boolean. However, the property $lastResult is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
605
		if (is_array($result))
606
		{
607
			return $result['ok'] > 0;
608
		}
609
		return $result;
610
	}
611
612
// <editor-fold defaultstate="collapsed" desc="Event and Signal handling">
613
614
	/**
615
	 * Take care of EventBeforeSave
616
	 * @see EventBeforeSave
617
	 * @param                 $model
618
	 * @param null|ModelEvent $event
619
	 * @return boolean
620
	 */
621
	private function beforeSave($model, $event = null)
622
	{
623
		AspectManager::addAspect($model, self::AspectSaving);
624
		$result = Event::Valid($model, EntityManagerInterface::EventBeforeSave);
625
		if ($result)
626
		{
627
			if (!empty($event))
628
			{
629
				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...
630
			}
631
			(new Signal)->emit(new BeforeSave($model));
632
		}
633
		return $result;
634
	}
635
636
	/**
637
	 * Take care of EventAfterSave
638
	 * @see EventAfterSave
639
	 * @param                 $model
640
	 * @param null|ModelEvent $event
641
	 */
642
	private function afterSave($model, $event = null)
643
	{
644
		Event::trigger($model, EntityManagerInterface::EventAfterSave);
645
		if (!empty($event))
646
		{
647
			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...
648
		}
649
		(new Signal)->emit(new AfterSave($model));
650
		ScenarioManager::setScenario($model, ScenariosInterface::Update);
651
		AspectManager::removeAspect($model, self::AspectSaving);
652
	}
653
654
	/**
655
	 * This method is invoked before deleting a record.
656
	 * The default implementation raises the {@link onBeforeDelete} event.
657
	 * You may override this method to do any preparation work for record deletion.
658
	 * Make sure you call the parent implementation so that the event is raised properly.
659
	 * @return boolean whether the record should be deleted. Defaults to true.
660
	 */
661
	private function beforeDelete()
662
	{
663
		AspectManager::addAspect($this->model, self::AspectRemoving);
664
		$result = Event::valid($this->model, EntityManagerInterface::EventBeforeDelete);
665
		if ($result)
666
		{
667
			(new Signal)->emit(new BeforeDelete($this->model));
668
			ScenarioManager::setScenario($this->model, ScenariosInterface::Delete);
669
		}
670
		return $result;
671
	}
672
673
	/**
674
	 * This method is invoked after deleting a record.
675
	 * The default implementation raises the {@link onAfterDelete} event.
676
	 * You may override this method to do postprocessing after the record is deleted.
677
	 * Make sure you call the parent implementation so that the event is raised properly.
678
	 */
679
	private function afterDelete()
680
	{
681
		$event = new ModelEvent($this->model);
682
		Event::trigger($this->model, EntityManagerInterface::EventAfterDelete, $event);
683
		(new Signal)->emit(new AfterDelete($this->model));
684
		AspectManager::removeAspect($this->model, self::AspectRemoving);
685
	}
686
687
// </editor-fold>
688
}
689