diff --git a/Loader/SymfonyFixturesLoader.php b/Loader/SymfonyFixturesLoader.php index c61c6356..90cfe4cf 100644 --- a/Loader/SymfonyFixturesLoader.php +++ b/Loader/SymfonyFixturesLoader.php @@ -13,6 +13,9 @@ use RuntimeException; use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader; use function array_key_exists; +use function array_map; +use function array_merge; +use function array_reduce; use function array_values; use function get_class; use function sprintf; @@ -116,6 +119,50 @@ public function getFixtures(array $groups = []) : array return array_values($filteredFixtures); } + /** + * @param (FixtureInterface|string)[] $fixtures + */ + public function getFixturesDependencyTree(array $fixtures) : array + { + $fixtures = array_map(static function ($fixture) { + if ($fixture instanceof FixtureInterface) { + return $fixture; + } + + return $this->createFixture($fixture); + }, $fixtures); + + $tree = $this->resolveFixturesDependencyTree($fixtures); + + return array_values($tree); + } + + /** + * @param FixtureInterface[] $fixtures + */ + private function resolveFixturesDependencyTree(array $fixtures) : array + { + return array_reduce($fixtures, function (array $tree, FixtureInterface $fixture) { + $class = get_class($fixture); + if (isset($tree[$class])) { + return $tree; + } + + $tree[$class] = $fixture; + if (! $fixture instanceof DependentFixtureInterface) { + return $tree; + } + + $dependencies = array_map(function (string $dependency) { + return $this->createFixture($dependency); + }, $fixture->getDependencies()); + + $subTree = $this->getFixturesDependencyTree($dependencies); + + return array_merge($subTree, $tree); + }, []); + } + /** * Generates an array of the groups and their fixtures * diff --git a/Tests/Loader/ResolveFixturesSubtreeTest.php b/Tests/Loader/ResolveFixturesSubtreeTest.php new file mode 100644 index 00000000..d550352d --- /dev/null +++ b/Tests/Loader/ResolveFixturesSubtreeTest.php @@ -0,0 +1,121 @@ +loader = new SymfonyFixturesLoader(new Container()); + } + + public function testGetBasicFixturesTree() : void + { + $fixtures = new OtherFixtures(); + $this->loader->addFixture($fixtures); + + $tree = $this->loader->getFixturesDependencyTree([$fixtures]); + + static::assertCount(1, $tree); + static::assertContains($fixtures, $tree); + } + + public function testResolveDependentFixtures() : void + { + $otherFixtures = new OtherFixtures(); + $this->loader->addFixture($otherFixtures); + + $withDependenciesFixtures = new WithDependenciesFixtures(); + $this->loader->addFixture($withDependenciesFixtures); + + $tree = $this->loader->getFixturesDependencyTree([$withDependenciesFixtures]); + + static::assertCount(2, $tree); + static::assertSame([$otherFixtures, $withDependenciesFixtures], $tree); + } + + public function testOmitFixturesOutsideTree() : void + { + $otherFixtures = new OtherFixtures(); + $this->loader->addFixture($otherFixtures); + + $withDependenciesFixtures = new WithDependenciesFixtures(); + $this->loader->addFixture($withDependenciesFixtures); + + $omittedFixtures = $this->createFixture([]); + $this->loader->addFixture($omittedFixtures); + + $tree = $this->loader->getFixturesDependencyTree([$withDependenciesFixtures]); + + static::assertCount(2, $tree); + static::assertSame([$otherFixtures, $withDependenciesFixtures], $tree); + } + + public function testResolveRecursively() : void + { + $otherFixtures = new OtherFixtures(); + $this->loader->addFixture($otherFixtures); + + $withDependenciesFixtures = new WithDependenciesFixtures(); + $this->loader->addFixture($withDependenciesFixtures); + + $treeTopFixtures = $this->createFixture([WithDependenciesFixtures::class]); + $this->loader->addFixture($treeTopFixtures); + + $tree = $this->loader->getFixturesDependencyTree([$treeTopFixtures]); + + static::assertCount(3, $tree); + static::assertSame([$otherFixtures, $withDependenciesFixtures, $treeTopFixtures], $tree); + } + + private function createFixture(array $dependencies) : FixtureInterface + { + return new class ($dependencies) implements FixtureInterface, DependentFixtureInterface { + /** @var string[] */ + private $dependencies; + + public function __construct(array $dependencies) + { + $this->dependencies = $dependencies; + } + + public function load(ObjectManager $manager) : void + { + } + + public function getDependencies() : array + { + return $this->dependencies; + } + }; + } +}