AddAutoMappingConfigurationPass.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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\Validator\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Reference;
  14. /**
  15. * Injects the automapping configuration as last argument of loaders tagged with the "validator.auto_mapper" tag.
  16. *
  17. * @author Kévin Dunglas <dunglas@gmail.com>
  18. */
  19. class AddAutoMappingConfigurationPass implements CompilerPassInterface
  20. {
  21. private $validatorBuilderService;
  22. private $tag;
  23. public function __construct(string $validatorBuilderService = 'validator.builder', string $tag = 'validator.auto_mapper')
  24. {
  25. $this->validatorBuilderService = $validatorBuilderService;
  26. $this->tag = $tag;
  27. }
  28. /**
  29. * {@inheritdoc}
  30. */
  31. public function process(ContainerBuilder $container)
  32. {
  33. if (!$container->hasParameter('validator.auto_mapping') || !$container->hasDefinition($this->validatorBuilderService)) {
  34. return;
  35. }
  36. $config = $container->getParameter('validator.auto_mapping');
  37. $globalNamespaces = [];
  38. $servicesToNamespaces = [];
  39. foreach ($config as $namespace => $value) {
  40. if ([] === $value['services']) {
  41. $globalNamespaces[] = $namespace;
  42. continue;
  43. }
  44. foreach ($value['services'] as $service) {
  45. $servicesToNamespaces[$service][] = $namespace;
  46. }
  47. }
  48. $validatorBuilder = $container->getDefinition($this->validatorBuilderService);
  49. foreach ($container->findTaggedServiceIds($this->tag) as $id => $tags) {
  50. $regexp = $this->getRegexp(array_merge($globalNamespaces, $servicesToNamespaces[$id] ?? []));
  51. $validatorBuilder->addMethodCall('addLoader', [new Reference($id)]);
  52. $container->getDefinition($id)->setArgument('$classValidatorRegexp', $regexp);
  53. }
  54. $container->getParameterBag()->remove('validator.auto_mapping');
  55. }
  56. /**
  57. * Builds a regexp to check if a class is auto-mapped.
  58. */
  59. private function getRegexp(array $patterns): ?string
  60. {
  61. if (!$patterns) {
  62. return null;
  63. }
  64. $regexps = [];
  65. foreach ($patterns as $pattern) {
  66. // Escape namespace
  67. $regex = preg_quote(ltrim($pattern, '\\'));
  68. // Wildcards * and **
  69. $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']);
  70. // If this class does not end by a slash, anchor the end
  71. if ('\\' !== substr($regex, -1)) {
  72. $regex .= '$';
  73. }
  74. $regexps[] = '^'.$regex;
  75. }
  76. return sprintf('{%s}', implode('|', $regexps));
  77. }
  78. }