vendor/zenstruck/foundry/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php line 54

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the zenstruck/foundry package.
  4. *
  5. * (c) Kevin Bond <kevinbond@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Zenstruck\Foundry\Bundle\DependencyInjection;
  11. use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
  12. use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
  13. use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
  14. use Symfony\Bundle\MakerBundle\MakerBundle;
  15. use Symfony\Component\Config\FileLocator;
  16. use Symfony\Component\DependencyInjection\ContainerBuilder;
  17. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  18. use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
  19. use Zenstruck\Foundry\Bundle\Command\StubMakeFactory;
  20. use Zenstruck\Foundry\Bundle\Command\StubMakeStory;
  21. use Zenstruck\Foundry\Factory;
  22. use Zenstruck\Foundry\Object\Instantiator;
  23. use Zenstruck\Foundry\Persistence\PersistentObjectFactory;
  24. use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
  25. use Zenstruck\Foundry\Story;
  26. use Zenstruck\Foundry\Test\ORMDatabaseResetter;
  27. use Zenstruck\Foundry\Test\ResetDatabase;
  28. /**
  29. * @author Kevin Bond <kevinbond@gmail.com>
  30. */
  31. final class ZenstruckFoundryExtension extends ConfigurableExtension
  32. {
  33. protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void
  34. {
  35. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  36. $loader->load('services.xml');
  37. $container->registerForAutoconfiguration(Story::class)
  38. ->addTag('foundry.story')
  39. ;
  40. $container->registerForAutoconfiguration(Factory::class)
  41. ->addTag('foundry.factory')
  42. ;
  43. $this->configureFaker($mergedConfig['faker'], $container);
  44. $this->configureDefaultInstantiator($mergedConfig['instantiator'], $container);
  45. $this->configureDatabaseResetter($mergedConfig, $container);
  46. $hasMakerBundle = \class_exists(AbstractMaker::class) && self::isBundleLoaded($container, MakerBundle::class);
  47. $this->configureServices($loader, $hasMakerBundle);
  48. $this->configureMakeFactory($mergedConfig['make_factory'], $container, $hasMakerBundle);
  49. $this->configureStoryFactory($mergedConfig['make_story'], $container, $hasMakerBundle);
  50. if (true === $mergedConfig['auto_refresh_proxies']) {
  51. $container->getDefinition('.zenstruck_foundry.configuration')->addMethodCall('enableDefaultProxyAutoRefresh');
  52. } elseif (false === $mergedConfig['auto_refresh_proxies']) {
  53. trigger_deprecation(
  54. 'zenstruck\foundry',
  55. '1.38.0',
  56. <<<MESSAGE
  57. Configuring the default proxy auto-refresh to false is deprecated. You should set it to "true", which will be the default value in 2.0.
  58. If you still want to disable auto refresh, make your factory implement "%s" instead of "%s".
  59. MESSAGE,
  60. PersistentObjectFactory::class,
  61. PersistentProxyObjectFactory::class,
  62. );
  63. $container->getDefinition('.zenstruck_foundry.configuration')->addMethodCall('disableDefaultProxyAutoRefresh');
  64. }
  65. }
  66. private function configureFaker(array $config, ContainerBuilder $container): void
  67. {
  68. if ($config['service']) {
  69. $container->setAlias('.zenstruck_foundry.faker', $config['service']);
  70. return;
  71. }
  72. $definition = $container->getDefinition('.zenstruck_foundry.faker');
  73. if ($config['locale']) {
  74. $definition->addArgument($config['locale']);
  75. }
  76. if ($config['seed']) {
  77. $definition->addMethodCall('seed', [$config['seed']]);
  78. }
  79. }
  80. private function configureDefaultInstantiator(array $config, ContainerBuilder $container): void
  81. {
  82. if ($config['service']) {
  83. $container->setAlias('.zenstruck_foundry.default_instantiator', $config['service']);
  84. return;
  85. }
  86. $definition = $container->getDefinition('.zenstruck_foundry.default_instantiator');
  87. if (isset($config['without_constructor'])
  88. && isset($config['use_constructor'])
  89. && $config['without_constructor'] === $config['use_constructor']
  90. ) {
  91. throw new \InvalidArgumentException('Cannot set "without_constructor" and "use_constructor" to the same value.');
  92. }
  93. $withoutConstructor = $config['without_constructor'] ?? !($config['use_constructor'] ?? true);
  94. $definition->setFactory([Instantiator::class, $withoutConstructor ? 'withoutConstructor' : 'withConstructor']);
  95. if ($config['allow_extra_attributes']) {
  96. $definition->addMethodCall('allowExtra');
  97. }
  98. if ($config['always_force_properties']) {
  99. $definition->addMethodCall('alwaysForce');
  100. }
  101. }
  102. private function configureDatabaseResetter(array $config, ContainerBuilder $container): void
  103. {
  104. $configurationDefinition = $container->getDefinition('.zenstruck_foundry.configuration');
  105. $legacyConfig = $config['database_resetter'];
  106. if (false === $legacyConfig['enabled']) {
  107. trigger_deprecation('zenstruck\foundry', '1.38.0', 'Disabling database reset via bundle configuration is deprecated and will be removed in 2.0. Instead you should not use "%s" trait in your test.', ResetDatabase::class);
  108. $configurationDefinition->addMethodCall('disableDatabaseReset');
  109. }
  110. if (isset($legacyConfig['orm']) && isset($config['orm']['reset'])) {
  111. throw new \InvalidArgumentException('Configurations "zenstruck_foundry.orm.reset" and "zenstruck_foundry.database_resetter.orm" are incompatible. You should only use "zenstruck_foundry.orm.reset".');
  112. }
  113. if ((isset($legacyConfig['orm']) || isset($config['orm']['reset'])) && !self::isBundleLoaded($container, DoctrineBundle::class)) {
  114. throw new \InvalidArgumentException('doctrine/doctrine-bundle should be enabled to use config under "orm.reset".');
  115. }
  116. if (isset($legacyConfig['odm']) && isset($config['mongo']['reset'])) {
  117. throw new \InvalidArgumentException('Configurations "zenstruck_foundry.mongo.reset" and "zenstruck_foundry.database_resetter.odm" are incompatible. You should only use "zenstruck_foundry.mongo.reset".');
  118. }
  119. if ((isset($legacyConfig['odm']) || isset($config['mongo']['reset'])) && !self::isBundleLoaded($container, DoctrineMongoDBBundle::class)) {
  120. throw new \InvalidArgumentException('doctrine/mongodb-odm-bundle should be enabled to use config under "mongo.reset".');
  121. }
  122. $configurationDefinition->setArgument('$ormConnectionsToReset', $legacyConfig['orm']['connections'] ?? $config['orm']['reset']['connections'] ?? ['default']);
  123. $configurationDefinition->setArgument('$ormObjectManagersToReset', $legacyConfig['orm']['object_managers'] ?? $config['orm']['reset']['entity_managers'] ?? ['default']);
  124. $configurationDefinition->setArgument('$ormResetMode', $legacyConfig['orm']['reset_mode'] ?? $config['orm']['reset']['mode'] ?? ORMDatabaseResetter::RESET_MODE_SCHEMA);
  125. $configurationDefinition->setArgument('$odmObjectManagersToReset', $legacyConfig['odm']['object_managers'] ?? $config['mongo']['reset']['document_managers'] ?? ['default']);
  126. }
  127. private function configureMakeFactory(array $makerConfig, ContainerBuilder $container, bool $hasMakerBundle): void
  128. {
  129. if (true === $hasMakerBundle) {
  130. $makeFactoryDefinition = $container->getDefinition('.zenstruck_foundry.maker.factory');
  131. $makeFactoryDefinition->setArgument('$defaultNamespace', $makerConfig['default_namespace']);
  132. } else {
  133. $container->register('.zenstruck_foundry.maker.factory_stub', StubMakeFactory::class)->addTag('console.command');
  134. }
  135. }
  136. private function configureStoryFactory(array $makerConfig, ContainerBuilder $container, bool $hasMakerBundle): void
  137. {
  138. if (true === $hasMakerBundle) {
  139. $makeFactoryDefinition = $container->getDefinition('.zenstruck_foundry.maker.story');
  140. $makeFactoryDefinition->setArgument('$defaultNamespace', $makerConfig['default_namespace']);
  141. } else {
  142. $container->register('.zenstruck_foundry.maker.story_stub', StubMakeStory::class)->addTag('console.command');
  143. }
  144. }
  145. private static function isBundleLoaded(ContainerBuilder $container, string $bundleName): bool
  146. {
  147. return \in_array(
  148. $bundleName,
  149. \is_array($bundles = $container->getParameter('kernel.bundles')) ? $bundles : [],
  150. true,
  151. );
  152. }
  153. private function configureServices(XmlFileLoader $loader, bool $hasMakerBundle): void
  154. {
  155. if (true === $hasMakerBundle) {
  156. $loader->load('maker.xml');
  157. }
  158. }
  159. }