vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php line 81

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\Component\DependencyInjection\Compiler;
  11. use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Definition;
  14. use Symfony\Component\DependencyInjection\Exception\LogicException;
  15. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  16. use Symfony\Component\DependencyInjection\ExpressionLanguage;
  17. use Symfony\Component\DependencyInjection\Reference;
  18. use Symfony\Component\ExpressionLanguage\Expression;
  19. /**
  20.  * @author Nicolas Grekas <p@tchwork.com>
  21.  */
  22. abstract class AbstractRecursivePass implements CompilerPassInterface
  23. {
  24.     /**
  25.      * @var ContainerBuilder
  26.      */
  27.     protected $container;
  28.     protected $currentId;
  29.     private $processExpressions false;
  30.     private $expressionLanguage;
  31.     private $inExpression false;
  32.     /**
  33.      * {@inheritdoc}
  34.      */
  35.     public function process(ContainerBuilder $container)
  36.     {
  37.         $this->container $container;
  38.         try {
  39.             $this->processValue($container->getDefinitions(), true);
  40.         } finally {
  41.             $this->container null;
  42.         }
  43.     }
  44.     protected function enableExpressionProcessing()
  45.     {
  46.         $this->processExpressions true;
  47.     }
  48.     protected function inExpression(bool $reset true): bool
  49.     {
  50.         $inExpression $this->inExpression;
  51.         if ($reset) {
  52.             $this->inExpression false;
  53.         }
  54.         return $inExpression;
  55.     }
  56.     /**
  57.      * Processes a value found in a definition tree.
  58.      *
  59.      * @param mixed $value
  60.      *
  61.      * @return mixed The processed value
  62.      */
  63.     protected function processValue($valuebool $isRoot false)
  64.     {
  65.         if (\is_array($value)) {
  66.             foreach ($value as $k => $v) {
  67.                 if ($isRoot) {
  68.                     $this->currentId $k;
  69.                 }
  70.                 if ($v !== $processedValue $this->processValue($v$isRoot)) {
  71.                     $value[$k] = $processedValue;
  72.                 }
  73.             }
  74.         } elseif ($value instanceof ArgumentInterface) {
  75.             $value->setValues($this->processValue($value->getValues()));
  76.         } elseif ($value instanceof Expression && $this->processExpressions) {
  77.             $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']);
  78.         } elseif ($value instanceof Definition) {
  79.             $value->setArguments($this->processValue($value->getArguments()));
  80.             $value->setProperties($this->processValue($value->getProperties()));
  81.             $value->setMethodCalls($this->processValue($value->getMethodCalls()));
  82.             $changes $value->getChanges();
  83.             if (isset($changes['factory'])) {
  84.                 $value->setFactory($this->processValue($value->getFactory()));
  85.             }
  86.             if (isset($changes['configurator'])) {
  87.                 $value->setConfigurator($this->processValue($value->getConfigurator()));
  88.             }
  89.         }
  90.         return $value;
  91.     }
  92.     /**
  93.      * @return \ReflectionFunctionAbstract|null
  94.      *
  95.      * @throws RuntimeException
  96.      */
  97.     protected function getConstructor(Definition $definitionbool $required)
  98.     {
  99.         if ($definition->isSynthetic()) {
  100.             return null;
  101.         }
  102.         if (\is_string($factory $definition->getFactory())) {
  103.             if (!\function_exists($factory)) {
  104.                 throw new RuntimeException(sprintf('Invalid service "%s": function "%s" does not exist.'$this->currentId$factory));
  105.             }
  106.             $r = new \ReflectionFunction($factory);
  107.             if (false !== $r->getFileName() && file_exists($r->getFileName())) {
  108.                 $this->container->fileExists($r->getFileName());
  109.             }
  110.             return $r;
  111.         }
  112.         if ($factory) {
  113.             [$class$method] = $factory;
  114.             if ($class instanceof Reference) {
  115.                 $class $this->container->findDefinition((string) $class)->getClass();
  116.             } elseif ($class instanceof Definition) {
  117.                 $class $class->getClass();
  118.             } elseif (null === $class) {
  119.                 $class $definition->getClass();
  120.             }
  121.             if ('__construct' === $method) {
  122.                 throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.'$this->currentId));
  123.             }
  124.             return $this->getReflectionMethod(new Definition($class), $method);
  125.         }
  126.         $class $definition->getClass();
  127.         try {
  128.             if (!$r $this->container->getReflectionClass($class)) {
  129.                 throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.'$this->currentId$class));
  130.             }
  131.         } catch (\ReflectionException $e) {
  132.             throw new RuntimeException(sprintf('Invalid service "%s": '$this->currentId).lcfirst($e->getMessage()));
  133.         }
  134.         if (!$r $r->getConstructor()) {
  135.             if ($required) {
  136.                 throw new RuntimeException(sprintf('Invalid service "%s": class%s has no constructor.'$this->currentIdsprintf($class !== $this->currentId ' "%s"' ''$class)));
  137.             }
  138.         } elseif (!$r->isPublic()) {
  139.             throw new RuntimeException(sprintf('Invalid service "%s": '$this->currentId).sprintf($class !== $this->currentId 'constructor of class "%s"' 'its constructor'$class).' must be public.');
  140.         }
  141.         return $r;
  142.     }
  143.     /**
  144.      * @throws RuntimeException
  145.      *
  146.      * @return \ReflectionFunctionAbstract
  147.      */
  148.     protected function getReflectionMethod(Definition $definitionstring $method)
  149.     {
  150.         if ('__construct' === $method) {
  151.             return $this->getConstructor($definitiontrue);
  152.         }
  153.         if (!$class $definition->getClass()) {
  154.             throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.'$this->currentId));
  155.         }
  156.         if (!$r $this->container->getReflectionClass($class)) {
  157.             throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.'$this->currentId$class));
  158.         }
  159.         if (!$r->hasMethod($method)) {
  160.             throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.'$this->currentId$class !== $this->currentId $class.'::'.$method $method));
  161.         }
  162.         $r $r->getMethod($method);
  163.         if (!$r->isPublic()) {
  164.             throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" must be public.'$this->currentId$class !== $this->currentId $class.'::'.$method $method));
  165.         }
  166.         return $r;
  167.     }
  168.     private function getExpressionLanguage(): ExpressionLanguage
  169.     {
  170.         if (null === $this->expressionLanguage) {
  171.             if (!class_exists(ExpressionLanguage::class)) {
  172.                 throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
  173.             }
  174.             $providers $this->container->getExpressionLanguageProviders();
  175.             $this->expressionLanguage = new ExpressionLanguage(null$providers, function (string $arg): string {
  176.                 if ('""' === substr_replace($arg''1, -1)) {
  177.                     $id stripcslashes(substr($arg1, -1));
  178.                     $this->inExpression true;
  179.                     $arg $this->processValue(new Reference($id));
  180.                     $this->inExpression false;
  181.                     if (!$arg instanceof Reference) {
  182.                         throw new RuntimeException(sprintf('"%s::processValue()" must return a Reference when processing an expression, "%s" returned for service("%s").', static::class, get_debug_type($arg), $id));
  183.                     }
  184.                     $arg sprintf('"%s"'$arg);
  185.                 }
  186.                 return sprintf('$this->get(%s)'$arg);
  187.             });
  188.         }
  189.         return $this->expressionLanguage;
  190.     }
  191. }