1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Blast Project package. |
5
|
|
|
* |
6
|
|
|
* Copyright (C) 2015-2017 Libre Informatique |
7
|
|
|
* |
8
|
|
|
* This file is licenced under the GNU LGPL v3. |
9
|
|
|
* For the full copyright and license information, please view the LICENSE.md |
10
|
|
|
* file that was distributed with this source code. |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace Blast\CoreBundle\Doctrine\ORM; |
14
|
|
|
|
15
|
|
|
use Doctrine\ORM\EntityManager; |
16
|
|
|
use Doctrine\ORM\Mapping\ClassMetadata; |
17
|
|
|
use Doctrine\Common\Collections\Collection; |
18
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccessor; |
19
|
|
|
|
20
|
|
|
class CascadingRelationChecker |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* @var EntityManager |
24
|
|
|
*/ |
25
|
|
|
private $em; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
private $undeleteReasons; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Hande entity relations before trying to remove it. |
34
|
|
|
* |
35
|
|
|
* @param mixed $entity a Doctrine entity object |
36
|
|
|
* @param array $idx list of entity ids to be removed |
37
|
|
|
* |
38
|
|
|
* @return |
39
|
|
|
*/ |
40
|
|
|
public function beforeEntityDelete($entity, &$idx) |
41
|
|
|
{ |
42
|
|
|
$this->undeleteReasons = []; |
43
|
|
|
|
44
|
|
|
$entityMetadata = $this->em->getClassMetadata(get_class($entity)); |
45
|
|
|
|
46
|
|
|
$associations = $entityMetadata->getAssociationMappings(); |
47
|
|
|
|
48
|
|
|
foreach ($associations as $association) { |
49
|
|
|
if (in_array('remove', $association['cascade'])) { |
50
|
|
|
continue; // Skip of cascading enabled |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
if (!in_array($association['type'], [ClassMetadata::ONE_TO_MANY])) { |
54
|
|
|
continue; // Handling only _TO_MANY relations |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
$propertyAccessor = new PropertyAccessor(); |
58
|
|
|
$associationData = $propertyAccessor->getValue($entity, $association['fieldName']); |
59
|
|
|
|
60
|
|
|
if ($associationData instanceof Collection) { |
61
|
|
|
if ($associationData->count() > 0) { |
62
|
|
|
$this->removeFromIdsArray($entityMetadata->getIdentifierValues($entity), $idx, $association); |
63
|
|
|
} |
64
|
|
|
} elseif ($associationData !== null) { |
65
|
|
|
$this->removeFromIdsArray($entityMetadata->getIdentifierValues($entity), $idx, $association); |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return $this->undeleteReasons; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
protected function removeFromIdsArray($id, &$idx, $association) |
73
|
|
|
{ |
74
|
|
|
$this->undeleteReasons[] = $association['fieldName']; |
75
|
|
|
|
76
|
|
|
foreach ($id as $k => $entityId) { |
77
|
|
|
foreach ($idx as $l => $idxId) { |
78
|
|
|
if ($idxId === $entityId) { |
79
|
|
|
unset($idx[$l]); |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @param EntityManager $em |
87
|
|
|
*/ |
88
|
|
|
public function setEm(EntityManager $em): void |
|
|
|
|
89
|
|
|
{ |
90
|
|
|
$this->em = $em; |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
The
EntityManager
might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:If that code throws an exception and the
EntityManager
is closed. Any other code which depends on the same instance of theEntityManager
during this request will fail.On the other hand, if you instead inject the
ManagerRegistry
, thegetManager()
method guarantees that you will always get a usable manager instance.