vendor/api-platform/core/src/Metadata/Extractor/AbstractResourceExtractor.php line 34

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the API Platform project.
  4. *
  5. * (c) Kévin Dunglas <dunglas@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. declare(strict_types=1);
  11. namespace ApiPlatform\Metadata\Extractor;
  12. use Psr\Container\ContainerInterface;
  13. use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface;
  14. /**
  15. * Base file extractor.
  16. *
  17. * @author Kévin Dunglas <dunglas@gmail.com>
  18. */
  19. abstract class AbstractResourceExtractor implements ResourceExtractorInterface
  20. {
  21. protected $paths;
  22. protected $resources;
  23. private $container;
  24. private $collectedParameters = [];
  25. /**
  26. * @param string[] $paths
  27. */
  28. public function __construct(array $paths, ContainerInterface $container = null)
  29. {
  30. $this->paths = $paths;
  31. $this->container = $container;
  32. }
  33. /**
  34. * {@inheritdoc}
  35. */
  36. public function getResources(): array
  37. {
  38. if (null !== $this->resources) {
  39. return $this->resources;
  40. }
  41. $this->resources = [];
  42. foreach ($this->paths as $path) {
  43. $this->extractPath($path);
  44. }
  45. return $this->resources;
  46. }
  47. /**
  48. * Extracts metadata from a given path.
  49. */
  50. abstract protected function extractPath(string $path);
  51. /**
  52. * Recursively replaces placeholders with the service container parameters.
  53. *
  54. * @see https://github.com/symfony/symfony/blob/6fec32c/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
  55. *
  56. * @copyright (c) Fabien Potencier <fabien@symfony.com>
  57. *
  58. * @param mixed $value The source which might contain "%placeholders%"
  59. *
  60. * @throws \RuntimeException When a container value is not a string or a numeric value
  61. *
  62. * @return mixed The source with the placeholders replaced by the container
  63. * parameters. Arrays are resolved recursively.
  64. */
  65. protected function resolve($value)
  66. {
  67. if (null === $this->container) {
  68. return $value;
  69. }
  70. if (\is_array($value)) {
  71. foreach ($value as $key => $val) {
  72. $value[$key] = $this->resolve($val);
  73. }
  74. return $value;
  75. }
  76. if (!\is_string($value)) {
  77. return $value;
  78. }
  79. $escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($value) {
  80. $parameter = $match[1] ?? null;
  81. // skip %%
  82. if (!isset($parameter)) {
  83. return '%%';
  84. }
  85. if (preg_match('/^env\(\w+\)$/', $parameter)) {
  86. throw new \RuntimeException(sprintf('Using "%%%s%%" is not allowed in routing configuration.', $parameter));
  87. }
  88. if (\array_key_exists($parameter, $this->collectedParameters)) {
  89. return $this->collectedParameters[$parameter];
  90. }
  91. if ($this->container instanceof SymfonyContainerInterface) {
  92. $resolved = $this->container->getParameter($parameter);
  93. } else {
  94. $resolved = $this->container->get($parameter);
  95. }
  96. if (\is_string($resolved) || is_numeric($resolved)) {
  97. $this->collectedParameters[$parameter] = $resolved;
  98. return (string) $resolved;
  99. }
  100. throw new \RuntimeException(sprintf('The container parameter "%s", used in the resource configuration value "%s", must be a string or numeric, but it is of type %s.', $parameter, $value, \gettype($resolved)));
  101. }, $value);
  102. return str_replace('%%', '%', $escapedValue);
  103. }
  104. }