FormPass.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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\Component\Form\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
  12. use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  13. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  14. use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
  15. use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
  16. use Symfony\Component\DependencyInjection\ContainerBuilder;
  17. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  18. use Symfony\Component\DependencyInjection\Reference;
  19. /**
  20. * Adds all services with the tags "form.type", "form.type_extension" and
  21. * "form.type_guesser" as arguments of the "form.extension" service.
  22. *
  23. * @author Bernhard Schussek <bschussek@gmail.com>
  24. */
  25. class FormPass implements CompilerPassInterface
  26. {
  27. use PriorityTaggedServiceTrait;
  28. private $formExtensionService;
  29. private $formTypeTag;
  30. private $formTypeExtensionTag;
  31. private $formTypeGuesserTag;
  32. private $formDebugCommandService;
  33. public function __construct(string $formExtensionService = 'form.extension', string $formTypeTag = 'form.type', string $formTypeExtensionTag = 'form.type_extension', string $formTypeGuesserTag = 'form.type_guesser', string $formDebugCommandService = 'console.command.form_debug')
  34. {
  35. $this->formExtensionService = $formExtensionService;
  36. $this->formTypeTag = $formTypeTag;
  37. $this->formTypeExtensionTag = $formTypeExtensionTag;
  38. $this->formTypeGuesserTag = $formTypeGuesserTag;
  39. $this->formDebugCommandService = $formDebugCommandService;
  40. }
  41. public function process(ContainerBuilder $container)
  42. {
  43. if (!$container->hasDefinition($this->formExtensionService)) {
  44. return;
  45. }
  46. $definition = $container->getDefinition($this->formExtensionService);
  47. $definition->replaceArgument(0, $this->processFormTypes($container));
  48. $definition->replaceArgument(1, $this->processFormTypeExtensions($container));
  49. $definition->replaceArgument(2, $this->processFormTypeGuessers($container));
  50. }
  51. private function processFormTypes(ContainerBuilder $container): Reference
  52. {
  53. // Get service locator argument
  54. $servicesMap = [];
  55. $namespaces = ['Symfony\Component\Form\Extension\Core\Type' => true];
  56. // Builds an array with fully-qualified type class names as keys and service IDs as values
  57. foreach ($container->findTaggedServiceIds($this->formTypeTag, true) as $serviceId => $tag) {
  58. // Add form type service to the service locator
  59. $serviceDefinition = $container->getDefinition($serviceId);
  60. $servicesMap[$formType = $serviceDefinition->getClass()] = new Reference($serviceId);
  61. $namespaces[substr($formType, 0, strrpos($formType, '\\'))] = true;
  62. }
  63. if ($container->hasDefinition($this->formDebugCommandService)) {
  64. $commandDefinition = $container->getDefinition($this->formDebugCommandService);
  65. $commandDefinition->setArgument(1, array_keys($namespaces));
  66. $commandDefinition->setArgument(2, array_keys($servicesMap));
  67. }
  68. return ServiceLocatorTagPass::register($container, $servicesMap);
  69. }
  70. private function processFormTypeExtensions(ContainerBuilder $container): array
  71. {
  72. $typeExtensions = [];
  73. $typeExtensionsClasses = [];
  74. foreach ($this->findAndSortTaggedServices($this->formTypeExtensionTag, $container) as $reference) {
  75. $serviceId = (string) $reference;
  76. $serviceDefinition = $container->getDefinition($serviceId);
  77. $tag = $serviceDefinition->getTag($this->formTypeExtensionTag);
  78. $typeExtensionClass = $container->getParameterBag()->resolveValue($serviceDefinition->getClass());
  79. if (isset($tag[0]['extended_type'])) {
  80. $typeExtensions[$tag[0]['extended_type']][] = new Reference($serviceId);
  81. $typeExtensionsClasses[] = $typeExtensionClass;
  82. } else {
  83. $extendsTypes = false;
  84. $typeExtensionsClasses[] = $typeExtensionClass;
  85. foreach ($typeExtensionClass::getExtendedTypes() as $extendedType) {
  86. $typeExtensions[$extendedType][] = new Reference($serviceId);
  87. $extendsTypes = true;
  88. }
  89. if (!$extendsTypes) {
  90. throw new InvalidArgumentException(sprintf('The getExtendedTypes() method for service "%s" does not return any extended types.', $serviceId));
  91. }
  92. }
  93. }
  94. foreach ($typeExtensions as $extendedType => $extensions) {
  95. $typeExtensions[$extendedType] = new IteratorArgument($extensions);
  96. }
  97. if ($container->hasDefinition($this->formDebugCommandService)) {
  98. $commandDefinition = $container->getDefinition($this->formDebugCommandService);
  99. $commandDefinition->setArgument(3, $typeExtensionsClasses);
  100. }
  101. return $typeExtensions;
  102. }
  103. private function processFormTypeGuessers(ContainerBuilder $container): ArgumentInterface
  104. {
  105. $guessers = [];
  106. $guessersClasses = [];
  107. foreach ($container->findTaggedServiceIds($this->formTypeGuesserTag, true) as $serviceId => $tags) {
  108. $guessers[] = new Reference($serviceId);
  109. $serviceDefinition = $container->getDefinition($serviceId);
  110. $guessersClasses[] = $serviceDefinition->getClass();
  111. }
  112. if ($container->hasDefinition($this->formDebugCommandService)) {
  113. $commandDefinition = $container->getDefinition($this->formDebugCommandService);
  114. $commandDefinition->setArgument(4, $guessersClasses);
  115. }
  116. return new IteratorArgument($guessers);
  117. }
  118. }