DataFixturesLoader   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 3
Bugs 2 Features 0
Metric Value
wmc 16
c 3
b 2
f 0
lcom 1
cbo 6
dl 0
loc 109
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B getFixtures() 0 30 6
A getAllFixtures() 0 9 2
C isFixtureAlreadyLoaded() 0 27 7
1
<?php
2
3
namespace RDV\Bundle\MigrationBundle\Migration\Loader;
4
5
use Doctrine\ORM\EntityManager;
6
use RDV\Bundle\MigrationBundle\Entity\DataFixture;
7
use RDV\Bundle\MigrationBundle\Fixture\VersionedFixtureInterface;
8
use RDV\Bundle\MigrationBundle\Migration\Sorter\DataFixturesSorter;
9
use RDV\Bundle\MigrationBundle\Migration\UpdateDataFixturesFixture;
10
use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
13
class DataFixturesLoader extends ContainerAwareLoader
14
{
15
    const MAIN_FIXTURES_TYPE = 'main';
16
    const DEMO_FIXTURES_TYPE = 'demo';
17
18
    /** @var EntityManager */
19
    protected $em;
20
21
    /** @var array */
22
    protected $loadedFixtures;
23
24
    /** @var \ReflectionProperty */
25
    protected $ref;
26
27
    /**
28
     * Constructor.
29
     *
30
     * @param EntityManager      $em
31
     * @param ContainerInterface $container
32
     */
33
    public function __construct(EntityManager $em, ContainerInterface $container)
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...
34
    {
35
        parent::__construct($container);
36
37
        $this->em = $em;
38
    }
39
40
    /**
41
     * @inheritdoc
42
     */
43
    public function getFixtures()
44
    {
45
        $sorter   = new DataFixturesSorter();
46
        $fixtures = $sorter->sort($this->getAllFixtures());
47
48
        // remove already loaded fixtures
49
        foreach ($fixtures as $key => $fixture) {
50
            if ($this->isFixtureAlreadyLoaded($fixture)) {
51
                unset($fixtures[$key]);
52
            }
53
        }
54
55
        // add a special fixture to mark new fixtures as "loaded"
56
        if (!empty($fixtures)) {
57
            $toBeLoadFixtureClassNames = [];
58
            foreach ($fixtures as $fixture) {
59
                $version = null;
60
                if ($fixture instanceof VersionedFixtureInterface) {
61
                    $version = $fixture->getVersion();
62
                }
63
                $toBeLoadFixtureClassNames[get_class($fixture)] = $version;
64
            }
65
66
            $updateFixture = new UpdateDataFixturesFixture();
67
            $updateFixture->setDataFixtures($toBeLoadFixtureClassNames);
68
            $fixtures[get_class($updateFixture)] = $updateFixture;
69
        }
70
71
        return $fixtures;
72
    }
73
74
    /**
75
     * Determines whether the given data fixture is already loaded or not
76
     *
77
     * @param object $fixtureObject
78
     *
79
     * @return bool
80
     */
81
    protected function isFixtureAlreadyLoaded($fixtureObject)
82
    {
83
        if (empty($this->loadedFixtures)) {
84
            $this->loadedFixtures = [];
85
86
            $loadedFixtures = $this->em->getRepository('RdvMigrationBundle:DataFixture')->findAll();
87
            /** @var DataFixture $fixture */
88
            foreach ($loadedFixtures as $fixture) {
89
                $this->loadedFixtures[$fixture->getClassName()] = $fixture->getVersion() ?: '0.0';
90
            }
91
        }
92
93
        $alreadyLoaded = false;
94
95
        if (isset($this->loadedFixtures[get_class($fixtureObject)])) {
96
            $alreadyLoaded = true;
97
            $loadedVersion = $this->loadedFixtures[get_class($fixtureObject)];
98
            if ($fixtureObject instanceof VersionedFixtureInterface
99
                && version_compare($loadedVersion, $fixtureObject->getVersion()) == -1
100
            ) {
101
                $fixtureObject->setLoadedVersion($loadedVersion);
102
                $alreadyLoaded = false;
103
            }
104
        }
105
106
        return $alreadyLoaded;
107
    }
108
109
    /**
110
     * @return array
111
     */
112
    protected function getAllFixtures()
113
    {
114
        if (!$this->ref) {
115
            $this->ref = new \ReflectionProperty('Doctrine\Common\DataFixtures\Loader', 'fixtures');
116
            $this->ref->setAccessible(true);
117
        }
118
119
        return $this->ref->getValue($this);
120
    }
121
}
122