Skip to content

Commit c3f9d40

Browse files
authored
Merge pull request #529 from arendjantetteroo/fixture-autowire
First implementation of symfony fixture loader + group support #461
2 parents 2d05efb + eeec626 commit c3f9d40

19 files changed

+875
-37
lines changed

Command/LoadDataFixturesDoctrineODMCommand.php

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace Doctrine\Bundle\MongoDBBundle\Command;
55

6+
use Doctrine\Bundle\MongoDBBundle\Loader\SymfonyFixturesLoaderInterface;
67
use Doctrine\Bundle\MongoDBBundle\ManagerRegistry;
78
use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor;
89
use Doctrine\Common\DataFixtures\Loader;
@@ -11,6 +12,7 @@
1112
use Symfony\Component\Console\Input\InputOption;
1213
use Symfony\Component\Console\Output\OutputInterface;
1314
use Symfony\Component\Console\Question\ConfirmationQuestion;
15+
use Symfony\Component\Console\Style\SymfonyStyle;
1416
use Symfony\Component\HttpKernel\KernelInterface;
1517

1618
/**
@@ -21,13 +23,22 @@
2123
*/
2224
class LoadDataFixturesDoctrineODMCommand extends DoctrineODMCommand
2325
{
26+
/**
27+
* @var KernelInterface
28+
*/
2429
private $kernel;
2530

26-
public function __construct(ManagerRegistry $registry = null, KernelInterface $kernel = null)
31+
/**
32+
* @var SymfonyFixturesLoaderInterface
33+
*/
34+
private $fixturesLoader;
35+
36+
public function __construct(ManagerRegistry $registry = null, KernelInterface $kernel = null, SymfonyFixturesLoaderInterface $fixturesLoader = null)
2737
{
2838
parent::__construct($registry);
2939

3040
$this->kernel = $kernel;
41+
$this->fixturesLoader = $fixturesLoader;
3142
}
3243

3344
/**
@@ -45,32 +56,45 @@ protected function configure()
4556
->setDescription('Load data fixtures to your database.')
4657
->addOption('fixtures', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The directory or file to load data fixtures from.')
4758
->addOption('bundles', 'b', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The bundles to load data fixtures from.')
59+
->addOption('services', null, InputOption::VALUE_NONE, 'Use services as fixtures')
60+
->addOption('group', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_REQUIRED, 'Only load fixtures that belong to this group (use with --services)')
4861
->addOption('append', null, InputOption::VALUE_NONE, 'Append the data fixtures instead of flushing the database first.')
4962
->addOption('dm', null, InputOption::VALUE_REQUIRED, 'The document manager to use for this command.')
5063
->setHelp(<<<EOT
51-
The <info>doctrine:mongodb:fixtures:load</info> command loads data fixtures from your bundles:
64+
The <info>doctrine:mongodb:fixtures:load</info> command loads data fixtures from your application:
5265
53-
<info>./app/console doctrine:mongodb:fixtures:load</info>
66+
<info>php %command.full_name%</info>
5467
5568
You can also optionally specify the path to fixtures with the <info>--fixtures</info> option:
56-
57-
<info>./app/console doctrine:mongodb:fixtures:load --fixtures=/path/to/fixtures1 --fixtures=/path/to/fixtures2</info>
69+
<info>php %command.full_name%</info> --fixtures=/path/to/fixtures1 --fixtures=/path/to/fixtures2</info>
5870
5971
If you want to append the fixtures instead of flushing the database first you can use the <info>--append</info> option:
6072
61-
<info>./app/console doctrine:mongodb:fixtures:load --append</info>
73+
<info>php %command.full_name%</info> --append</info>
74+
75+
76+
Alternatively, you can also load fixture services instead of files. Fixture services are tagged with `<comment>doctrine.fixture.odm</comment>`.
77+
When using `<comment>--services</comment>`, both `<comment>--fixtures</comment>` and `<comment>--bundles</comment>` will no longer work.
78+
Using `<comment>--services</comment>` will be the default behaviour in 4.0.
79+
When loading fixture services, you can also choose to load only fixtures that live in a certain group:
80+
`<info>php %command.full_name%</info> <comment>--group=group1</comment> <comment>--services</comment>`
81+
82+
83+
6284
EOT
6385
);
6486
}
6587

6688
protected function execute(InputInterface $input, OutputInterface $output)
6789
{
6890
$dm = $this->getManagerRegistry()->getManager($input->getOption('dm'));
91+
$ui = new SymfonyStyle($input, $output);
6992

7093
$dirOrFile = $input->getOption('fixtures');
7194
$bundles = $input->getOption('bundles');
72-
if ($bundles && $dirOrFile) {
73-
throw new \InvalidArgumentException('Use only one option: --bundles or --fixtures.');
95+
$services = (bool) $input->getOption('services');
96+
if (($services && $bundles) || ($services && $dirOrFile) || ($bundles && $dirOrFile)) {
97+
throw new \InvalidArgumentException('Can only use one of "--bundles", "--fixtures", "--services".');
7498
}
7599

76100
if ($input->isInteractive() && !$input->getOption('append')) {
@@ -82,37 +106,57 @@ protected function execute(InputInterface $input, OutputInterface $output)
82106
}
83107
}
84108

85-
if ($dirOrFile) {
86-
$paths = is_array($dirOrFile) ? $dirOrFile : [$dirOrFile];
87-
} elseif ($bundles) {
88-
$paths = [$this->getKernel()->getRootDir().'/DataFixtures/MongoDB'];
89-
foreach ($bundles as $bundle) {
90-
$paths[] = $this->getKernel()->getBundle($bundle)->getPath();
109+
if (!$services) {
110+
@trigger_error('--bundles and --fixtures are deprecated since doctrine/mongodb-odm-bundle 3.6 and will be removed in 4.0. Use --services instead.', E_USER_DEPRECATED);
111+
112+
if ($dirOrFile) {
113+
$paths = is_array($dirOrFile) ? $dirOrFile : [$dirOrFile];
114+
} elseif ($bundles) {
115+
$paths = [$this->getKernel()->getRootDir().'/DataFixtures/MongoDB'];
116+
foreach ($bundles as $bundle) {
117+
$paths[] = $this->getKernel()->getBundle($bundle)->getPath();
118+
}
119+
} else {
120+
$paths = $this->container->getParameter('doctrine_mongodb.odm.fixtures_dirs');
121+
$paths = is_array($paths) ? $paths : [$paths];
122+
$paths[] = $this->getKernel()->getRootDir().'/DataFixtures/MongoDB';
123+
foreach ($this->getKernel()->getBundles() as $bundle) {
124+
$paths[] = $bundle->getPath().'/DataFixtures/MongoDB';
125+
}
126+
}
127+
$loaderClass = $this->container->getParameter('doctrine_mongodb.odm.fixture_loader');
128+
$loader = new $loaderClass($this->container);
129+
foreach ($paths as $path) {
130+
if (is_dir($path)) {
131+
$loader->loadFromDirectory($path);
132+
} else if (is_file($path)) {
133+
$loader->loadFromFile($path);
134+
}
135+
}
136+
$fixtures = $loader->getFixtures();
137+
if (!$fixtures) {
138+
throw new \InvalidArgumentException(
139+
sprintf('Could not find any fixtures to load in: %s', "\n\n- ".implode("\n- ", $paths))
140+
);
91141
}
92142
} else {
93-
$paths = $this->container->getParameter('doctrine_mongodb.odm.fixtures_dirs');
94-
$paths = is_array($paths) ? $paths : [$paths];
95-
$paths[] = $this->getKernel()->getRootDir().'/DataFixtures/MongoDB';
96-
foreach ($this->getKernel()->getBundles() as $bundle) {
97-
$paths[] = $bundle->getPath().'/DataFixtures/MongoDB';
143+
if (! $this->fixturesLoader) {
144+
throw new \RuntimeException('Cannot use fixture services without injecting a fixtures loader.');
98145
}
99-
}
100146

101-
$loaderClass = $this->container->getParameter('doctrine_mongodb.odm.fixture_loader');
102-
$loader = new $loaderClass($this->container);
103-
foreach ($paths as $path) {
104-
if (is_dir($path)) {
105-
$loader->loadFromDirectory($path);
106-
} else if (is_file($path)) {
107-
$loader->loadFromFile($path);
108-
}
109-
}
147+
$groups = $input->getOption('group');
148+
$fixtures = $this->fixturesLoader->getFixtures($groups);
149+
if (! $fixtures) {
150+
$message = 'Could not find any fixture services to load';
151+
152+
if (! empty($groups)) {
153+
$message .= sprintf(' in the groups (%s)', implode(', ', $groups));
154+
}
110155

111-
$fixtures = $loader->getFixtures();
112-
if (!$fixtures) {
113-
throw new \InvalidArgumentException(
114-
sprintf('Could not find any fixtures to load in: %s', "\n\n- ".implode("\n- ", $paths))
115-
);
156+
$ui->error($message . '.');
157+
158+
return 1;
159+
}
116160
}
117161

118162
$purger = new MongoDBPurger($dm);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Doctrine Fixtures Bundle
5+
*
6+
* The code was originally distributed inside the Symfony framework.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
* (c) Doctrine Project
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler;
16+
17+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18+
use Symfony\Component\DependencyInjection\ContainerBuilder;
19+
use Symfony\Component\DependencyInjection\Reference;
20+
21+
final class FixturesCompilerPass implements CompilerPassInterface
22+
{
23+
const FIXTURE_TAG = 'doctrine.fixture.odm.mongodb';
24+
25+
public function process(ContainerBuilder $container)
26+
{
27+
$definition = $container->getDefinition('doctrine_mongodb.odm.symfony.fixtures.loader');
28+
$taggedServices = $container->findTaggedServiceIds(self::FIXTURE_TAG);
29+
30+
$fixtures = [];
31+
foreach ($taggedServices as $serviceId => $tags) {
32+
$groups = [];
33+
foreach ($tags as $tagData) {
34+
if (! isset($tagData['group'])) {
35+
continue;
36+
}
37+
38+
$groups[] = $tagData['group'];
39+
}
40+
41+
$fixtures[] = [
42+
'fixture' => new Reference($serviceId),
43+
'groups' => $groups,
44+
];
45+
}
46+
47+
$definition->addMethodCall('addFixtures', [$fixtures]);
48+
}
49+
}

DependencyInjection/DoctrineMongoDBExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
namespace Doctrine\Bundle\MongoDBBundle\DependencyInjection;
55

6+
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\FixturesCompilerPass;
67
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
8+
use Doctrine\Bundle\MongoDBBundle\Fixture\ODMFixtureInterface;
79
use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepositoryInterface;
810
use Doctrine\Common\EventSubscriber;
911
use Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension;
@@ -57,6 +59,10 @@ public function load(array $configs, ContainerBuilder $container)
5759
// set the fixtures loader
5860
$container->setParameter('doctrine_mongodb.odm.fixture_loader', $config['fixture_loader']);
5961

62+
// Autowiring fixture loader
63+
$container->registerForAutoconfiguration(ODMFixtureInterface::class)
64+
->addTag(FixturesCompilerPass::FIXTURE_TAG);
65+
6066
// load the connections
6167
$this->loadConnections($config['connections'], $container);
6268

DoctrineMongoDBBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace Doctrine\Bundle\MongoDBBundle;
55

6+
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\FixturesCompilerPass;
67
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
78
use Doctrine\Common\Util\ClassUtils;
89
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\CreateHydratorDirectoryPass;
@@ -33,6 +34,7 @@ public function build(ContainerBuilder $container)
3334
$container->addCompilerPass(new CreateHydratorDirectoryPass(), PassConfig::TYPE_BEFORE_REMOVING);
3435
$container->addCompilerPass(new DoctrineValidationPass('mongodb'));
3536
$container->addCompilerPass(new ServiceRepositoryCompilerPass());
37+
$container->addCompilerPass(new FixturesCompilerPass());
3638

3739
if ($container->hasExtension('security')) {
3840
$container->getExtension('security')->addUserProviderFactory(new EntityFactory('mongodb', 'doctrine_mongodb.odm.security.user.provider'));

Fixture/Fixture.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Doctrine\Bundle\MongoDBBundle\Fixture;
4+
5+
use Doctrine\Common\DataFixtures\AbstractFixture;
6+
7+
/**
8+
* Base class designed for data fixtures so they don't have to extend and
9+
* implement different classes/interfaces according to their needs.
10+
*/
11+
abstract class Fixture extends AbstractFixture implements ODMFixtureInterface
12+
{
13+
}

Fixture/FixtureGroupInterface.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Doctrine\Bundle\MongoDBBundle\Fixture;
4+
5+
/**
6+
* FixtureGroupInterface can be implemented by fixtures that belong in groups
7+
*/
8+
interface FixtureGroupInterface
9+
{
10+
/**
11+
* This method must return an array of groups
12+
* on which the implementing class belongs to
13+
*
14+
* @return string[]
15+
*/
16+
public static function getGroups();
17+
}

Fixture/ODMFixtureInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Doctrine\Bundle\MongoDBBundle\Fixture;
4+
5+
use Doctrine\Common\DataFixtures\FixtureInterface;
6+
7+
/**
8+
* Marks your fixtures that are specifically for the ODM.
9+
*/
10+
interface ODMFixtureInterface extends FixtureInterface
11+
{
12+
}

0 commit comments

Comments
 (0)