CascadingRelationChecker   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 12
c 2
b 0
f 0
lcom 1
cbo 4
dl 0
loc 73
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
C beforeEntityDelete() 0 31 7
A removeFromIdsArray() 0 12 4
A setEm() 0 4 1
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
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...
89
    {
90
        $this->em = $em;
91
    }
92
}
93