-
-
Notifications
You must be signed in to change notification settings - Fork 201
/
SymfonyFixturesLoader.php
151 lines (127 loc) · 4.66 KB
/
SymfonyFixturesLoader.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<?php
declare(strict_types=1);
namespace Doctrine\Bundle\FixturesBundle\Loader;
use Doctrine\Bundle\FixturesBundle\DependencyInjection\CompilerPass\FixturesCompilerPass;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Common\DataFixtures\FixtureInterface;
use LogicException;
use ReflectionClass;
use RuntimeException;
use function array_key_exists;
use function array_values;
use function get_class;
use function sprintf;
final class SymfonyFixturesLoader extends SymfonyBridgeLoader
{
/** @var FixtureInterface[] */
private array $loadedFixtures = [];
/** @var array<string, array<string, bool>> */
private array $groupsFixtureMapping = [];
/**
* @internal
*
* @psalm-param list<array{fixture: FixtureInterface, groups: list<string>}> $fixtures
*/
public function addFixtures(array $fixtures): void
{
// Because parent::addFixture may call $this->createFixture
// we cannot call $this->addFixture in this loop
foreach ($fixtures as $fixture) {
$class = get_class($fixture['fixture']);
$this->loadedFixtures[$class] = $fixture['fixture'];
$this->addGroupsFixtureMapping($class, $fixture['groups']);
}
// Now that all fixtures are in the $this->loadedFixtures array,
// it is safe to call $this->addFixture in this loop
foreach ($this->loadedFixtures as $fixture) {
$this->addFixture($fixture);
}
}
public function addFixture(FixtureInterface $fixture): void
{
$class = get_class($fixture);
$this->loadedFixtures[$class] = $fixture;
$reflection = new ReflectionClass($fixture);
$this->addGroupsFixtureMapping($class, [$reflection->getShortName()]);
if ($fixture instanceof FixtureGroupInterface) {
$this->addGroupsFixtureMapping($class, $fixture::getGroups());
}
parent::addFixture($fixture);
}
/**
* Overridden to not allow new fixture classes to be instantiated.
* {@inheritDoc}
*/
protected function createFixture($class): FixtureInterface
{
/*
* We don't actually need to create the fixture. We just
* return the one that already exists.
*/
if (! isset($this->loadedFixtures[$class])) {
throw new LogicException(sprintf(
'The "%s" fixture class is trying to be loaded, but is not available. Make sure this class is defined as a service and tagged with "%s".',
$class,
FixturesCompilerPass::FIXTURE_TAG,
));
}
return $this->loadedFixtures[$class];
}
/**
* Returns the array of data fixtures to execute.
*
* @param string[] $groups
*
* @return FixtureInterface[]
*/
public function getFixtures(array $groups = []): array
{
$fixtures = parent::getFixtures();
if (empty($groups)) {
return $fixtures;
}
$filteredFixtures = [];
foreach ($fixtures as $fixture) {
foreach ($groups as $group) {
$fixtureClass = get_class($fixture);
if (isset($this->groupsFixtureMapping[$group][$fixtureClass])) {
$filteredFixtures[$fixtureClass] = $fixture;
continue 2;
}
}
}
foreach ($filteredFixtures as $fixture) {
$this->validateDependencies($filteredFixtures, $fixture);
}
return array_values($filteredFixtures);
}
/**
* Generates an array of the groups and their fixtures
*
* @param string[] $groups
*/
private function addGroupsFixtureMapping(string $className, array $groups): void
{
foreach ($groups as $group) {
$this->groupsFixtureMapping[$group][$className] = true;
}
}
/**
* @param string[] $fixtures An array of fixtures with class names as keys
*
* @throws RuntimeException
*/
private function validateDependencies(array $fixtures, FixtureInterface $fixture): void
{
if (! $fixture instanceof DependentFixtureInterface) {
return;
}
$dependenciesClasses = $fixture->getDependencies();
foreach ($dependenciesClasses as $class) {
if (! array_key_exists($class, $fixtures)) {
throw new RuntimeException(sprintf('Fixture "%s" was declared as a dependency for fixture "%s", but it was not included in any of the loaded fixture groups.', $class, get_class($fixture)));
}
}
}
}