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) |
|
|
|
|
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
|
|
|
|
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.