vendor/symfony/ux-twig-component/src/DependencyInjection/TwigComponentExtension.php line 176

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.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 Symfony\UX\TwigComponent\DependencyInjection;
  11. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  12. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  13. use Symfony\Component\Config\Definition\ConfigurationInterface;
  14. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  15. use Symfony\Component\Config\FileLocator;
  16. use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
  17. use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
  18. use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
  19. use Symfony\Component\DependencyInjection\ChildDefinition;
  20. use Symfony\Component\DependencyInjection\ContainerBuilder;
  21. use Symfony\Component\DependencyInjection\ContainerInterface;
  22. use Symfony\Component\DependencyInjection\Exception\LogicException;
  23. use Symfony\Component\DependencyInjection\Extension\Extension;
  24. use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
  25. use Symfony\Component\DependencyInjection\Parameter;
  26. use Symfony\Component\DependencyInjection\Reference;
  27. use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
  28. use Symfony\UX\TwigComponent\CacheWarmer\TwigComponentCacheWarmer;
  29. use Symfony\UX\TwigComponent\Command\TwigComponentDebugCommand;
  30. use Symfony\UX\TwigComponent\ComponentFactory;
  31. use Symfony\UX\TwigComponent\ComponentProperties;
  32. use Symfony\UX\TwigComponent\ComponentRenderer;
  33. use Symfony\UX\TwigComponent\ComponentRendererInterface;
  34. use Symfony\UX\TwigComponent\ComponentStack;
  35. use Symfony\UX\TwigComponent\ComponentTemplateFinder;
  36. use Symfony\UX\TwigComponent\DependencyInjection\Compiler\TwigComponentPass;
  37. use Symfony\UX\TwigComponent\Twig\ComponentExtension;
  38. use Symfony\UX\TwigComponent\Twig\ComponentLexer;
  39. use Symfony\UX\TwigComponent\Twig\ComponentRuntime;
  40. use Symfony\UX\TwigComponent\Twig\TwigEnvironmentConfigurator;
  41. /**
  42. * @author Kevin Bond <kevinbond@gmail.com>
  43. *
  44. * @internal
  45. */
  46. final class TwigComponentExtension extends Extension implements ConfigurationInterface
  47. {
  48. private const DEPRECATED_DEFAULT_KEY = '__deprecated__use_old_naming_behavior';
  49. public function load(array $configs, ContainerBuilder $container): void
  50. {
  51. $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
  52. if (!isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
  53. throw new LogicException('The TwigBundle is not registered in your application. Try running "composer require symfony/twig-bundle".');
  54. }
  55. $configuration = $this->getConfiguration($configs, $container);
  56. $config = $this->processConfiguration($configuration, $configs);
  57. $defaults = $config['defaults'];
  58. if ($defaults === [self::DEPRECATED_DEFAULT_KEY]) {
  59. trigger_deprecation('symfony/ux-twig-component', '2.13', 'Not setting the "twig_component.defaults" config option is deprecated. Check the documentation for an example configuration.');
  60. $container->setParameter('ux.twig_component.legacy_autonaming', true);
  61. $defaults = [];
  62. }
  63. $container->setParameter('ux.twig_component.component_defaults', $defaults);
  64. $container->register('ux.twig_component.component_template_finder', ComponentTemplateFinder::class)
  65. ->setArguments([
  66. new Reference('twig.loader'),
  67. $config['anonymous_template_directory'],
  68. ]);
  69. $container->setAlias(ComponentRendererInterface::class, 'ux.twig_component.component_renderer');
  70. $container->registerAttributeForAutoconfiguration(
  71. AsTwigComponent::class,
  72. static function (ChildDefinition $definition, AsTwigComponent $attribute) {
  73. $definition->addTag('twig.component', array_filter($attribute->serviceConfig()));
  74. }
  75. );
  76. $container->register('ux.twig_component.component_factory', ComponentFactory::class)
  77. ->setArguments([
  78. new Reference('ux.twig_component.component_template_finder'),
  79. new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
  80. new Reference('property_accessor'),
  81. new Reference('event_dispatcher'),
  82. new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
  83. new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
  84. new Reference('twig'),
  85. ])
  86. ->addTag('kernel.reset', ['method' => 'reset'])
  87. ;
  88. $container->register('ux.twig_component.component_stack', ComponentStack::class);
  89. $container->register('ux.twig_component.component_properties', ComponentProperties::class)
  90. ->setArguments([
  91. new Reference('property_accessor'),
  92. new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
  93. new Reference('cache.ux.twig_component', ContainerInterface::IGNORE_ON_INVALID_REFERENCE),
  94. ])
  95. ;
  96. $container->register('ux.twig_component.component_renderer', ComponentRenderer::class)
  97. ->setArguments([
  98. new Reference('twig'),
  99. new Reference('event_dispatcher'),
  100. new Reference('ux.twig_component.component_factory'),
  101. new Reference('ux.twig_component.component_properties'),
  102. new Reference('ux.twig_component.component_stack'),
  103. ])
  104. ->addTag('kernel.reset', ['method' => 'reset'])
  105. ;
  106. $container->register('ux.twig_component.twig.component_extension', ComponentExtension::class)
  107. ->addTag('twig.extension')
  108. ;
  109. $container->register('ux.twig_component.twig.component_runtime', ComponentRuntime::class)
  110. ->setArguments([
  111. new Reference('ux.twig_component.component_renderer'),
  112. new ServiceLocatorArgument(new TaggedIteratorArgument('ux.twig_component.twig_renderer', indexAttribute: 'key', needsIndexes: true)),
  113. ])
  114. ->addTag('twig.runtime')
  115. ;
  116. $container->register('ux.twig_component.twig.lexer', ComponentLexer::class);
  117. $container->register('ux.twig_component.twig.environment_configurator', TwigEnvironmentConfigurator::class)
  118. ->setDecoratedService(new Reference('twig.configurator.environment'))
  119. ->setArguments([new Reference('ux.twig_component.twig.environment_configurator.inner')]);
  120. $container->register('ux.twig_component.command.debug', TwigComponentDebugCommand::class)
  121. ->setArguments([
  122. new Parameter('twig.default_path'),
  123. new Reference('ux.twig_component.component_factory'),
  124. new Reference('twig'),
  125. new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
  126. $config['anonymous_template_directory'],
  127. ])
  128. ->addTag('console.command')
  129. ;
  130. $container->setAlias('console.command.stimulus_component_debug', 'ux.twig_component.command.debug')
  131. ->setDeprecated('symfony/ux-twig-component', '2.13', '%alias_id%');
  132. if ($container->getParameter('kernel.debug') && $config['profiler']) {
  133. $loader->load('debug.php');
  134. }
  135. $loader->load('cache.php');
  136. $container->register('ux.twig_component.cache_warmer', TwigComponentCacheWarmer::class)
  137. ->setArguments([new Reference(\Psr\Container\ContainerInterface::class)])
  138. ->addTag('kernel.cache_warmer')
  139. ->addTag('container.service_subscriber', ['id' => 'ux.twig_component.component_properties'])
  140. ;
  141. }
  142. public function getConfigTreeBuilder(): TreeBuilder
  143. {
  144. $treeBuilder = new TreeBuilder('twig_component');
  145. $rootNode = $treeBuilder->getRootNode();
  146. \assert($rootNode instanceof ArrayNodeDefinition);
  147. $rootNode
  148. ->validate()
  149. ->always(function ($v) {
  150. if (!isset($v['anonymous_template_directory'])) {
  151. trigger_deprecation('symfony/twig-component-bundle', '2.13', 'Not setting the "twig_component.anonymous_template_directory" config option is deprecated. It will default to "components" in 3.0.');
  152. $v['anonymous_template_directory'] = null;
  153. }
  154. return $v;
  155. })
  156. ->end()
  157. ->children()
  158. ->arrayNode('defaults')
  159. ->defaultValue([self::DEPRECATED_DEFAULT_KEY])
  160. ->useAttributeAsKey('namespace')
  161. ->validate()
  162. ->always(function ($v) {
  163. foreach ($v as $namespace => $defaults) {
  164. if (!str_ends_with($namespace, '\\')) {
  165. throw new InvalidConfigurationException(\sprintf('The twig_component.defaults namespace "%s" is invalid: it must end in a "\".', $namespace));
  166. }
  167. }
  168. return $v;
  169. })
  170. ->end()
  171. ->arrayPrototype()
  172. ->beforeNormalization()
  173. ->ifString()
  174. ->then(function (string $v) {
  175. return ['template_directory' => $v];
  176. })
  177. ->end()
  178. ->children()
  179. ->scalarNode('template_directory')
  180. ->defaultValue('components')
  181. ->end()
  182. ->scalarNode('name_prefix')
  183. ->defaultValue('')
  184. ->end()
  185. ->end()
  186. ->end()
  187. ->end()
  188. ->scalarNode('anonymous_template_directory')
  189. ->info('Defaults to `components`')
  190. ->end()
  191. ->booleanNode('profiler')
  192. ->info('Enables the profiler for Twig Component (in debug mode)')
  193. ->defaultValue('%kernel.debug%')
  194. ->end()
  195. ->scalarNode('controllers_json')
  196. ->setDeprecated('symfony/ux-twig-component', '2.18', 'The "twig_component.controllers_json" config option is deprecated, and will be removed in 3.0.')
  197. ->defaultNull()
  198. ->end()
  199. ->end();
  200. return $treeBuilder;
  201. }
  202. public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
  203. {
  204. return $this;
  205. }
  206. }