Completed
Push — wip-platform ( 03cba6...2999ab )
by
unknown
05:53 queued 02:49
created

CascadingRelationChecker::beforeEntityDelete()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 17
nc 7
nop 2
1
<?php
2
3
/*
4
 *
5
 * Copyright (C) 2015-2017 Libre Informatique
6
 *
7
 * This file is licenced under the GNU LGPL v3.
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Blast\Bundle\CoreBundle\Doctrine\ORM;
13
14
use Doctrine\ORM\EntityManager;
15
use Doctrine\ORM\Mapping\ClassMetadata;
16
use Doctrine\Common\Collections\Collection;
17
use Symfony\Component\PropertyAccess\PropertyAccessor;
18
19
class CascadingRelationChecker
20
{
21
    /**
22
     * @var EntityManager
23
     */
24
    private $em;
25
26
    /**
27
     * @var array
28
     */
29
    private $undeleteReasons;
30
31
    /**
32
     * Hande entity relations before trying to remove it.
33
     *
34
     * @param mixed $entity a Doctrine entity object
35
     * @param array $idx    list of entity ids to be removed
36
     *
37
     * @return
38
     */
39
    public function beforeEntityDelete($entity, &$idx)
40
    {
41
        $this->undeleteReasons = [];
42
43
        $entityMetadata = $this->em->getClassMetadata(get_class($entity));
44
45
        $associations = $entityMetadata->getAssociationMappings();
46
47
        foreach ($associations as $association) {
48
            if (in_array('remove', $association['cascade'])) {
49
                continue; // Skip of cascading enabled
50
            }
51
52
            if (!in_array($association['type'], [ClassMetadata::ONE_TO_MANY])) {
53
                continue; // Handling only _TO_MANY relations
54
            }
55
56
            $propertyAccessor = new PropertyAccessor();
57
            $associationData = $propertyAccessor->getValue($entity, $association['fieldName']);
58
59
            if ($associationData instanceof Collection) {
60
                if ($associationData->count() > 0) {
61
                    $this->removeFromIdsArray($entityMetadata->getIdentifierValues($entity), $idx, $association);
62
                }
63
            } elseif ($associationData !== null) {
64
                $this->removeFromIdsArray($entityMetadata->getIdentifierValues($entity), $idx, $association);
65
            }
66
        }
67
68
        return $this->undeleteReasons;
69
    }
70
71
    protected function removeFromIdsArray($id, &$idx, $association)
72
    {
73
        $this->undeleteReasons[] = $association['fieldName'];
74
75
        foreach ($id as $k => $entityId) {
76
            foreach ($idx as $l => $idxId) {
77
                if ($idxId === $entityId) {
78
                    unset($idx[$l]);
79
                }
80
            }
81
        }
82
    }
83
84
    /**
85
     * @param EntityManager $em
86
     */
87
    public function setEm(EntityManager $em): void
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

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:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
88
    {
89
        $this->em = $em;
90
    }
91
}
92