init
This commit is contained in:
257
backend/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php
vendored
Normal file
257
backend/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\ExpressionLanguage;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractRecursivePass implements CompilerPassInterface
|
||||
{
|
||||
protected ?ContainerBuilder $container;
|
||||
protected ?string $currentId = null;
|
||||
protected bool $skipScalars = false;
|
||||
|
||||
private bool $processExpressions = false;
|
||||
private ExpressionLanguage $expressionLanguage;
|
||||
private bool $inExpression = false;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
try {
|
||||
$this->processValue($container->getDefinitions(), true);
|
||||
} finally {
|
||||
$this->container = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function enableExpressionProcessing(): void
|
||||
{
|
||||
$this->processExpressions = true;
|
||||
}
|
||||
|
||||
protected function inExpression(bool $reset = true): bool
|
||||
{
|
||||
$inExpression = $this->inExpression;
|
||||
if ($reset) {
|
||||
$this->inExpression = false;
|
||||
}
|
||||
|
||||
return $inExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a value found in a definition tree.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function processValue(mixed $value, bool $isRoot = false)
|
||||
{
|
||||
if (\is_array($value)) {
|
||||
foreach ($value as $k => $v) {
|
||||
if ((!$v || \is_scalar($v)) && $this->skipScalars) {
|
||||
continue;
|
||||
}
|
||||
if ($isRoot) {
|
||||
if ($v instanceof Definition && $v->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
$this->currentId = $k;
|
||||
}
|
||||
if ($v !== $processedValue = $this->processValue($v, $isRoot)) {
|
||||
$value[$k] = $processedValue;
|
||||
}
|
||||
}
|
||||
} elseif ($value instanceof ArgumentInterface) {
|
||||
$value->setValues($this->processValue($value->getValues()));
|
||||
} elseif ($value instanceof Expression && $this->processExpressions) {
|
||||
$this->getExpressionLanguage()->compile((string) $value, ['this' => 'container', 'args' => 'args']);
|
||||
} elseif ($value instanceof Definition) {
|
||||
$value->setArguments($this->processValue($value->getArguments()));
|
||||
$value->setProperties($this->processValue($value->getProperties()));
|
||||
$value->setMethodCalls($this->processValue($value->getMethodCalls()));
|
||||
|
||||
$changes = $value->getChanges();
|
||||
if (isset($changes['factory'])) {
|
||||
if (\is_string($factory = $value->getFactory()) && str_starts_with($factory, '@=')) {
|
||||
if (!class_exists(Expression::class)) {
|
||||
throw new LogicException('Expressions cannot be used in service factories without the ExpressionLanguage component. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
$factory = new Expression(substr($factory, 2));
|
||||
}
|
||||
if (($factory = $this->processValue($factory)) instanceof Expression) {
|
||||
$factory = '@='.$factory;
|
||||
}
|
||||
$value->setFactory($factory);
|
||||
}
|
||||
if (isset($changes['configurator'])) {
|
||||
$value->setConfigurator($this->processValue($value->getConfigurator()));
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function getConstructor(Definition $definition, bool $required): ?\ReflectionFunctionAbstract
|
||||
{
|
||||
if ($definition->isSynthetic()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (\is_string($factory = $definition->getFactory())) {
|
||||
if (str_starts_with($factory, '@=')) {
|
||||
return new \ReflectionFunction(static function (...$args) {});
|
||||
}
|
||||
|
||||
if (!\function_exists($factory)) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": function "%s" does not exist.', $this->currentId, $factory));
|
||||
}
|
||||
$r = new \ReflectionFunction($factory);
|
||||
if (false !== $r->getFileName() && file_exists($r->getFileName())) {
|
||||
$this->container->fileExists($r->getFileName());
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
if ($factory) {
|
||||
[$class, $method] = $factory;
|
||||
|
||||
if ('__construct' === $method) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
|
||||
}
|
||||
|
||||
if ($class instanceof Reference) {
|
||||
$factoryDefinition = $this->container->findDefinition((string) $class);
|
||||
while ((null === $class = $factoryDefinition->getClass()) && $factoryDefinition instanceof ChildDefinition) {
|
||||
$factoryDefinition = $this->container->findDefinition($factoryDefinition->getParent());
|
||||
}
|
||||
} elseif ($class instanceof Definition) {
|
||||
$class = $class->getClass();
|
||||
} else {
|
||||
$class ??= $definition->getClass();
|
||||
}
|
||||
|
||||
return $this->getReflectionMethod(new Definition($class), $method);
|
||||
}
|
||||
|
||||
while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
|
||||
$definition = $this->container->findDefinition($definition->getParent());
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$r = $this->container->getReflectionClass($class)) {
|
||||
if (null === $class) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": the class is not set.', $this->currentId));
|
||||
}
|
||||
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": ', $this->currentId).lcfirst($e->getMessage()));
|
||||
}
|
||||
if (!$r = $r->getConstructor()) {
|
||||
if ($required) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": class%s has no constructor.', $this->currentId, \sprintf($class !== $this->currentId ? ' "%s"' : '', $class)));
|
||||
}
|
||||
} elseif (!$r->isPublic()) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": ', $this->currentId).\sprintf($class !== $this->currentId ? 'constructor of class "%s"' : 'its constructor', $class).' must be public. Did you miss configuring a factory or a static constructor? Try using the "#[Autoconfigure(constructor: ...)]" attribute for the latter.');
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function getReflectionMethod(Definition $definition, string $method): \ReflectionFunctionAbstract
|
||||
{
|
||||
if ('__construct' === $method) {
|
||||
return $this->getConstructor($definition, true);
|
||||
}
|
||||
|
||||
while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) {
|
||||
$definition = $this->container->findDefinition($definition->getParent());
|
||||
}
|
||||
|
||||
if (null === $class) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": the class is not set.', $this->currentId));
|
||||
}
|
||||
|
||||
if (!$r = $this->container->getReflectionClass($class)) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
|
||||
}
|
||||
|
||||
if (!$r->hasMethod($method)) {
|
||||
if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) {
|
||||
return new \ReflectionMethod(static function (...$arguments) {}, '__invoke');
|
||||
}
|
||||
|
||||
if ($r->hasMethod('__callStatic') && ($r = $r->getMethod('__callStatic')) && $r->isPublic()) {
|
||||
return new \ReflectionMethod(static function (...$arguments) {}, '__invoke');
|
||||
}
|
||||
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
|
||||
$r = $r->getMethod($method);
|
||||
if (!$r->isPublic()) {
|
||||
throw new RuntimeException(\sprintf('Invalid service "%s": method "%s()" must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function getExpressionLanguage(): ExpressionLanguage
|
||||
{
|
||||
if (!isset($this->expressionLanguage)) {
|
||||
if (!class_exists(ExpressionLanguage::class)) {
|
||||
throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
|
||||
$providers = $this->container->getExpressionLanguageProviders();
|
||||
$this->expressionLanguage = new ExpressionLanguage(null, $providers, function (string $arg): string {
|
||||
if ('""' === substr_replace($arg, '', 1, -1)) {
|
||||
$id = stripcslashes(substr($arg, 1, -1));
|
||||
$this->inExpression = true;
|
||||
$arg = $this->processValue(new Reference($id));
|
||||
$this->inExpression = false;
|
||||
if (!$arg instanceof Reference) {
|
||||
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));
|
||||
}
|
||||
$arg = \sprintf('"%s"', $arg);
|
||||
}
|
||||
|
||||
return \sprintf('$this->get(%s)', $arg);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
}
|
||||
61
backend/vendor/symfony/dependency-injection/Compiler/AliasDeprecatedPublicServicesPass.php
vendored
Normal file
61
backend/vendor/symfony/dependency-injection/Compiler/AliasDeprecatedPublicServicesPass.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
final class AliasDeprecatedPublicServicesPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $aliases = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->findTaggedServiceIds('container.private') as $id => $tags) {
|
||||
if (null === $package = $tags[0]['package'] ?? null) {
|
||||
throw new InvalidArgumentException(\sprintf('The "package" attribute is mandatory for the "container.private" tag on the "%s" service.', $id));
|
||||
}
|
||||
|
||||
if (null === $version = $tags[0]['version'] ?? null) {
|
||||
throw new InvalidArgumentException(\sprintf('The "version" attribute is mandatory for the "container.private" tag on the "%s" service.', $id));
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition($id);
|
||||
if ($definition->isPrivate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container
|
||||
->setAlias($id, $aliasId = '.container.private.'.$id)
|
||||
->setPublic(true)
|
||||
->setDeprecated($package, $version, 'Accessing the "%alias_id%" service directly from the container is deprecated, use dependency injection instead.');
|
||||
|
||||
$container->setDefinition($aliasId, $definition);
|
||||
|
||||
$this->aliases[$id] = $aliasId;
|
||||
}
|
||||
|
||||
parent::process($container);
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference && isset($this->aliases[$id = (string) $value])) {
|
||||
return new Reference($this->aliases[$id], $value->getInvalidBehavior());
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
211
backend/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php
vendored
Normal file
211
backend/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
/**
|
||||
* Run this pass before passes that need to know more about the relation of
|
||||
* your services.
|
||||
*
|
||||
* This class will populate the ServiceReferenceGraph with information. You can
|
||||
* retrieve the graph in other passes from the compiler.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class AnalyzeServiceReferencesPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private ServiceReferenceGraph $graph;
|
||||
private ?Definition $currentDefinition = null;
|
||||
private bool $lazy;
|
||||
private bool $byConstructor;
|
||||
private bool $byFactory;
|
||||
private bool $byMultiUseArgument;
|
||||
private array $definitions;
|
||||
private array $aliases;
|
||||
|
||||
/**
|
||||
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
|
||||
*/
|
||||
public function __construct(
|
||||
private bool $onlyConstructorArguments = false,
|
||||
private bool $hasProxyDumper = true,
|
||||
) {
|
||||
$this->enableExpressionProcessing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a ContainerBuilder object to populate the service reference graph.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
$this->graph->clear();
|
||||
$this->lazy = false;
|
||||
$this->byConstructor = false;
|
||||
$this->byFactory = false;
|
||||
$this->byMultiUseArgument = false;
|
||||
$this->definitions = $container->getDefinitions();
|
||||
$this->aliases = $container->getAliases();
|
||||
|
||||
foreach ($this->aliases as $id => $alias) {
|
||||
$targetId = $this->getDefinitionId((string) $alias);
|
||||
$this->graph->connect($id, $alias, $targetId, null !== $targetId ? $this->container->getDefinition($targetId) : null, null);
|
||||
}
|
||||
|
||||
try {
|
||||
parent::process($container);
|
||||
} finally {
|
||||
$this->aliases = $this->definitions = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
$lazy = $this->lazy;
|
||||
$inExpression = $this->inExpression();
|
||||
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
$this->lazy = !$this->byFactory || !$value instanceof IteratorArgument;
|
||||
$byMultiUseArgument = $this->byMultiUseArgument;
|
||||
if ($value instanceof IteratorArgument) {
|
||||
$this->byMultiUseArgument = true;
|
||||
}
|
||||
parent::processValue($value->getValues());
|
||||
$this->byMultiUseArgument = $byMultiUseArgument;
|
||||
$this->lazy = $lazy;
|
||||
|
||||
return $value;
|
||||
}
|
||||
if ($value instanceof Reference) {
|
||||
$targetId = $this->getDefinitionId((string) $value);
|
||||
$targetDefinition = null !== $targetId ? $this->container->getDefinition($targetId) : null;
|
||||
|
||||
$this->graph->connect(
|
||||
$this->currentId,
|
||||
$this->currentDefinition,
|
||||
$targetId,
|
||||
$targetDefinition,
|
||||
$value,
|
||||
$this->lazy || ($this->hasProxyDumper && $targetDefinition?->isLazy()),
|
||||
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior(),
|
||||
$this->byConstructor,
|
||||
$this->byMultiUseArgument
|
||||
);
|
||||
|
||||
if ($inExpression) {
|
||||
$this->graph->connect(
|
||||
'.internal.reference_in_expression',
|
||||
null,
|
||||
$targetId,
|
||||
$targetDefinition,
|
||||
$value,
|
||||
$this->lazy || $targetDefinition?->isLazy(),
|
||||
true,
|
||||
$this->byConstructor,
|
||||
$this->byMultiUseArgument
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
if ($isRoot) {
|
||||
if ($value->isSynthetic() || $value->isAbstract()) {
|
||||
return $value;
|
||||
}
|
||||
$this->currentDefinition = $value;
|
||||
} elseif ($this->currentDefinition === $value) {
|
||||
return $value;
|
||||
}
|
||||
$this->lazy = false;
|
||||
|
||||
$byConstructor = $this->byConstructor;
|
||||
$this->byConstructor = $isRoot || $byConstructor;
|
||||
|
||||
$byFactory = $this->byFactory;
|
||||
$this->byFactory = true;
|
||||
if (\is_string($factory = $value->getFactory()) && str_starts_with($factory, '@=')) {
|
||||
if (!class_exists(Expression::class)) {
|
||||
throw new LogicException('Expressions cannot be used in service factories without the ExpressionLanguage component. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
|
||||
$factory = new Expression(substr($factory, 2));
|
||||
}
|
||||
$this->processValue($factory);
|
||||
$this->byFactory = $byFactory;
|
||||
|
||||
$this->processValue($value->getArguments());
|
||||
|
||||
$properties = $value->getProperties();
|
||||
$setters = $value->getMethodCalls();
|
||||
|
||||
// Any references before a "wither" are part of the constructor-instantiation graph
|
||||
$lastWitherIndex = null;
|
||||
foreach ($setters as $k => $call) {
|
||||
if ($call[2] ?? false) {
|
||||
$lastWitherIndex = $k;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $lastWitherIndex) {
|
||||
$this->processValue($properties);
|
||||
$setters = $properties = [];
|
||||
|
||||
foreach ($value->getMethodCalls() as $k => $call) {
|
||||
if (null === $lastWitherIndex) {
|
||||
$setters[] = $call;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($lastWitherIndex === $k) {
|
||||
$lastWitherIndex = null;
|
||||
}
|
||||
|
||||
$this->processValue($call);
|
||||
}
|
||||
}
|
||||
|
||||
$this->byConstructor = $byConstructor;
|
||||
|
||||
if (!$this->onlyConstructorArguments) {
|
||||
$this->processValue($properties);
|
||||
$this->processValue($setters);
|
||||
$this->processValue($value->getConfigurator());
|
||||
}
|
||||
$this->lazy = $lazy;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function getDefinitionId(string $id): ?string
|
||||
{
|
||||
while (isset($this->aliases[$id])) {
|
||||
$id = (string) $this->aliases[$id];
|
||||
}
|
||||
|
||||
return isset($this->definitions[$id]) ? $id : null;
|
||||
}
|
||||
}
|
||||
169
backend/vendor/symfony/dependency-injection/Compiler/AttributeAutoconfigurationPass.php
vendored
Normal file
169
backend/vendor/symfony/dependency-injection/Compiler/AttributeAutoconfigurationPass.php
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*/
|
||||
final class AttributeAutoconfigurationPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $classAttributeConfigurators = [];
|
||||
private array $methodAttributeConfigurators = [];
|
||||
private array $propertyAttributeConfigurators = [];
|
||||
private array $parameterAttributeConfigurators = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->getAttributeAutoconfigurators()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container->getAttributeAutoconfigurators() as $attributeName => $callables) {
|
||||
foreach ($callables as $callable) {
|
||||
$callableReflector = new \ReflectionFunction($callable(...));
|
||||
if ($callableReflector->getNumberOfParameters() <= 2) {
|
||||
$this->classAttributeConfigurators[$attributeName][] = $callable;
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflectorParameter = $callableReflector->getParameters()[2];
|
||||
$parameterType = $reflectorParameter->getType();
|
||||
$types = [];
|
||||
if ($parameterType instanceof \ReflectionUnionType) {
|
||||
foreach ($parameterType->getTypes() as $type) {
|
||||
$types[] = $type->getName();
|
||||
}
|
||||
} elseif ($parameterType instanceof \ReflectionNamedType) {
|
||||
$types[] = $parameterType->getName();
|
||||
} else {
|
||||
throw new LogicException(\sprintf('Argument "$%s" of attribute autoconfigurator should have a type, use one or more of "\ReflectionClass|\ReflectionMethod|\ReflectionProperty|\ReflectionParameter|\Reflector" in "%s" on line "%d".', $reflectorParameter->getName(), $callableReflector->getFileName(), $callableReflector->getStartLine()));
|
||||
}
|
||||
|
||||
foreach (['Class', 'Method', 'Property', 'Parameter'] as $symbol) {
|
||||
if (['Reflector'] === $types || \in_array('Reflection'.$symbol, $types, true)) {
|
||||
$this->{lcfirst($symbol).'AttributeConfigurators'}[$attributeName][] = $callable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->container = $container;
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$this->currentId = $id;
|
||||
$this->processValue($definition, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Definition
|
||||
|| !$value->isAutoconfigured()
|
||||
|| ($value->isAbstract() && !$value->hasTag('container.excluded'))
|
||||
|| $value->hasTag('container.ignore_attributes')
|
||||
|| !($classReflector = $this->container->getReflectionClass($value->getClass(), false))
|
||||
) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$instanceof = $value->getInstanceofConditionals();
|
||||
$conditionals = $instanceof[$classReflector->getName()] ?? new ChildDefinition('');
|
||||
|
||||
$this->callConfigurators($this->classAttributeConfigurators, $conditionals, $classReflector);
|
||||
|
||||
if ($this->parameterAttributeConfigurators) {
|
||||
try {
|
||||
$constructorReflector = $this->getConstructor($value, false);
|
||||
} catch (RuntimeException) {
|
||||
$constructorReflector = null;
|
||||
}
|
||||
|
||||
if ($constructorReflector) {
|
||||
foreach ($constructorReflector->getParameters() as $parameterReflector) {
|
||||
$this->callConfigurators($this->parameterAttributeConfigurators, $conditionals, $parameterReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->methodAttributeConfigurators || $this->parameterAttributeConfigurators) {
|
||||
foreach ($classReflector->getMethods(\ReflectionMethod::IS_PUBLIC) as $methodReflector) {
|
||||
if ($methodReflector->isConstructor() || $methodReflector->isDestructor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->callConfigurators($this->methodAttributeConfigurators, $conditionals, $methodReflector);
|
||||
|
||||
foreach ($methodReflector->getParameters() as $parameterReflector) {
|
||||
$this->callConfigurators($this->parameterAttributeConfigurators, $conditionals, $parameterReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->propertyAttributeConfigurators) {
|
||||
foreach ($classReflector->getProperties(\ReflectionProperty::IS_PUBLIC) as $propertyReflector) {
|
||||
if ($propertyReflector->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->callConfigurators($this->propertyAttributeConfigurators, $conditionals, $propertyReflector);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($instanceof[$classReflector->getName()]) && new ChildDefinition('') != $conditionals) {
|
||||
$instanceof[$classReflector->getName()] = $conditionals;
|
||||
$value->setInstanceofConditionals($instanceof);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call all the configurators for the given attribute.
|
||||
*
|
||||
* @param array<class-string, callable[]> $configurators
|
||||
*/
|
||||
private function callConfigurators(array &$configurators, ChildDefinition $conditionals, \ReflectionClass|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflector): void
|
||||
{
|
||||
if (!$configurators) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($reflector->getAttributes() as $attribute) {
|
||||
foreach ($this->findConfigurators($configurators, $attribute->getName()) as $configurator) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $reflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first configurator for the given attribute name, looking up the class hierarchy.
|
||||
*/
|
||||
private function findConfigurators(array &$configurators, string $attributeName): array
|
||||
{
|
||||
if (\array_key_exists($attributeName, $configurators)) {
|
||||
return $configurators[$attributeName];
|
||||
}
|
||||
|
||||
if (class_exists($attributeName) && $parent = get_parent_class($attributeName)) {
|
||||
return $configurators[$attributeName] = $this->findConfigurators($configurators, $parent);
|
||||
}
|
||||
|
||||
return $configurators[$attributeName] = [];
|
||||
}
|
||||
}
|
||||
39
backend/vendor/symfony/dependency-injection/Compiler/AutoAliasServicePass.php
vendored
Normal file
39
backend/vendor/symfony/dependency-injection/Compiler/AutoAliasServicePass.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Sets a service to be an alias of another one, given a format pattern.
|
||||
*/
|
||||
class AutoAliasServicePass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->findTaggedServiceIds('auto_alias') as $serviceId => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
if (!isset($tag['format'])) {
|
||||
throw new InvalidArgumentException(\sprintf('Missing tag information "format" on auto_alias service "%s".', $serviceId));
|
||||
}
|
||||
|
||||
$aliasId = $container->getParameterBag()->resolveValue($tag['format']);
|
||||
if ($container->hasDefinition($aliasId) || $container->hasAlias($aliasId)) {
|
||||
$alias = new Alias($aliasId, $container->getDefinition($serviceId)->isPublic());
|
||||
$container->setAlias($serviceId, $alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
backend/vendor/symfony/dependency-injection/Compiler/AutowireAsDecoratorPass.php
vendored
Normal file
61
backend/vendor/symfony/dependency-injection/Compiler/AutowireAsDecoratorPass.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* Reads #[AsDecorator] attributes on definitions that are autowired
|
||||
* and don't have the "container.ignore_attributes" tag.
|
||||
*/
|
||||
final class AutowireAsDecoratorPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($this->accept($definition) && $reflectionClass = $container->getReflectionClass($definition->getClass(), false)) {
|
||||
$this->processClass($id, $container, $definition, $reflectionClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function accept(Definition $definition): bool
|
||||
{
|
||||
return !$definition->hasTag('container.ignore_attributes') && $definition->isAutowired();
|
||||
}
|
||||
|
||||
private function processClass(string $id, ContainerBuilder $container, Definition $definition, \ReflectionClass $reflectionClass): void
|
||||
{
|
||||
if (!$attributes = $reflectionClass->getAttributes(AsDecorator::class, \ReflectionAttribute::IS_INSTANCEOF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (1 === \count($attributes)) {
|
||||
$attribute = $attributes[0]->newInstance();
|
||||
$definition->setDecoratedService($attribute->decorates, null, $attribute->priority, $attribute->onInvalid);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$attribute = $attribute->newInstance();
|
||||
|
||||
$definition = clone $definition;
|
||||
$definition->setDecoratedService($attribute->decorates, null, $attribute->priority, $attribute->onInvalid);
|
||||
$container->setDefinition(\sprintf('.decorator.%s.%s', $attribute->decorates, $id), $definition);
|
||||
}
|
||||
|
||||
$container->removeDefinition($id);
|
||||
}
|
||||
}
|
||||
771
backend/vendor/symfony/dependency-injection/Compiler/AutowirePass.php
vendored
Normal file
771
backend/vendor/symfony/dependency-injection/Compiler/AutowirePass.php
vendored
Normal file
@@ -0,0 +1,771 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireInline;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Lazy;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* Inspects existing service definitions and wires the autowired ones using the type hints of their classes.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class AutowirePass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $types;
|
||||
private array $ambiguousServiceTypes;
|
||||
private array $autowiringAliases;
|
||||
private ?string $lastFailure = null;
|
||||
private ?string $decoratedClass = null;
|
||||
private ?string $decoratedId = null;
|
||||
private object $defaultArgument;
|
||||
private ?\Closure $restorePreviousValue = null;
|
||||
private ?self $typesClone = null;
|
||||
|
||||
public function __construct(
|
||||
private bool $throwOnAutowiringException = true,
|
||||
) {
|
||||
$this->defaultArgument = new class {
|
||||
public $value;
|
||||
public $names;
|
||||
public $bag;
|
||||
|
||||
public function withValue(\ReflectionParameter $parameter): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->value = $this->bag->escapeValue($parameter->getDefaultValue());
|
||||
|
||||
return $clone;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->defaultArgument->bag = $container->getParameterBag();
|
||||
|
||||
try {
|
||||
$this->typesClone = clone $this;
|
||||
parent::process($container);
|
||||
} finally {
|
||||
$this->decoratedClass = null;
|
||||
$this->decoratedId = null;
|
||||
$this->defaultArgument->bag = null;
|
||||
$this->defaultArgument->names = null;
|
||||
$this->restorePreviousValue = null;
|
||||
$this->typesClone = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Autowire) {
|
||||
return $this->processValue($this->container->getParameterBag()->resolveValue($value->value));
|
||||
}
|
||||
|
||||
if ($value instanceof AutowireDecorated) {
|
||||
$definition = $this->container->getDefinition($this->currentId);
|
||||
|
||||
return new Reference($definition->innerServiceId ?? $this->currentId.'.inner', $definition->decorationOnInvalid ?? ContainerInterface::NULL_ON_INVALID_REFERENCE);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->doProcessValue($value, $isRoot);
|
||||
} catch (AutowiringFailedException $e) {
|
||||
if ($this->throwOnAutowiringException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->container->getDefinition($this->currentId)->addError($e->getMessageCallback() ?? $e->getMessage());
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
|
||||
private function doProcessValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof TypedReference) {
|
||||
foreach ($value->getAttributes() as $attribute) {
|
||||
if ($attribute === $v = $this->processValue($attribute)) {
|
||||
continue;
|
||||
}
|
||||
if (!$attribute instanceof Autowire || !$v instanceof Reference) {
|
||||
return $v;
|
||||
}
|
||||
|
||||
$invalidBehavior = ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE !== $v->getInvalidBehavior() ? $v->getInvalidBehavior() : $value->getInvalidBehavior();
|
||||
$value = $v instanceof TypedReference
|
||||
? new TypedReference($v, $v->getType(), $invalidBehavior, $v->getName() ?? $value->getName(), array_merge($v->getAttributes(), $value->getAttributes()))
|
||||
: new TypedReference($v, $value->getType(), $invalidBehavior, $value->getName(), $value->getAttributes());
|
||||
break;
|
||||
}
|
||||
if ($ref = $this->getAutowiredReference($value, true)) {
|
||||
return $ref;
|
||||
}
|
||||
if (ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
|
||||
$message = $this->createTypeNotFoundMessageCallback($value, 'it');
|
||||
|
||||
// since the error message varies by referenced id and $this->currentId, so should the id of the dummy errored definition
|
||||
$this->container->register($id = \sprintf('.errored.%s.%s', $this->currentId, (string) $value), $value->getType())
|
||||
->addError($message);
|
||||
|
||||
return new TypedReference($id, $value->getType(), $value->getInvalidBehavior(), $value->getName());
|
||||
}
|
||||
}
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||
return $value;
|
||||
}
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
|
||||
$this->container->log($this, \sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
$methodCalls = $value->getMethodCalls();
|
||||
|
||||
try {
|
||||
$constructor = $this->getConstructor($value, false);
|
||||
} catch (RuntimeException $e) {
|
||||
throw new AutowiringFailedException($this->currentId, $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if ($constructor) {
|
||||
array_unshift($methodCalls, [$constructor, $value->getArguments()]);
|
||||
}
|
||||
|
||||
$checkAttributes = !$value->hasTag('container.ignore_attributes');
|
||||
$methodCalls = $this->autowireCalls($methodCalls, $reflectionClass, $isRoot, $checkAttributes);
|
||||
|
||||
if ($constructor) {
|
||||
[, $arguments] = array_shift($methodCalls);
|
||||
|
||||
if ($arguments !== $value->getArguments()) {
|
||||
$value->setArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
if ($methodCalls !== $value->getMethodCalls()) {
|
||||
$value->setMethodCalls($methodCalls);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function autowireCalls(array $methodCalls, \ReflectionClass $reflectionClass, bool $isRoot, bool $checkAttributes): array
|
||||
{
|
||||
if ($isRoot) {
|
||||
$this->decoratedId = null;
|
||||
$this->decoratedClass = null;
|
||||
$this->restorePreviousValue = null;
|
||||
|
||||
if (($definition = $this->container->getDefinition($this->currentId)) && null !== ($this->decoratedId = $definition->innerServiceId) && $this->container->has($this->decoratedId)) {
|
||||
$this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass();
|
||||
}
|
||||
}
|
||||
|
||||
$patchedIndexes = [];
|
||||
|
||||
foreach ($methodCalls as $i => $call) {
|
||||
[$method, $arguments] = $call;
|
||||
|
||||
if ($method instanceof \ReflectionFunctionAbstract) {
|
||||
$reflectionMethod = $method;
|
||||
} else {
|
||||
$definition = new Definition($reflectionClass->name);
|
||||
try {
|
||||
$reflectionMethod = $this->getReflectionMethod($definition, $method);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($definition->getFactory()) {
|
||||
continue;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$arguments = $this->autowireMethod($reflectionMethod, $arguments, $checkAttributes);
|
||||
|
||||
if ($arguments !== $call[1]) {
|
||||
$methodCalls[$i][1] = $arguments;
|
||||
$patchedIndexes[] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// use named arguments to skip complex default values
|
||||
foreach ($patchedIndexes as $i) {
|
||||
$namedArguments = null;
|
||||
$arguments = $methodCalls[$i][1];
|
||||
|
||||
foreach ($arguments as $j => $value) {
|
||||
if ($namedArguments && !$value instanceof $this->defaultArgument) {
|
||||
unset($arguments[$j]);
|
||||
$arguments[$namedArguments[$j]] = $value;
|
||||
}
|
||||
if (!$value instanceof $this->defaultArgument) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\is_array($value->value) ? $value->value : \is_object($value->value)) {
|
||||
unset($arguments[$j]);
|
||||
$namedArguments = $value->names;
|
||||
}
|
||||
|
||||
if ($namedArguments) {
|
||||
unset($arguments[$j]);
|
||||
} else {
|
||||
$arguments[$j] = $value->value;
|
||||
}
|
||||
}
|
||||
|
||||
$methodCalls[$i][1] = $arguments;
|
||||
}
|
||||
|
||||
return $methodCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowires the constructor or a method.
|
||||
*
|
||||
* @throws AutowiringFailedException
|
||||
*/
|
||||
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes): array
|
||||
{
|
||||
$class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId;
|
||||
$method = $reflectionMethod->name;
|
||||
$parameters = $reflectionMethod->getParameters();
|
||||
if ($reflectionMethod->isVariadic()) {
|
||||
array_pop($parameters);
|
||||
}
|
||||
$defaultArgument = clone $this->defaultArgument;
|
||||
$defaultArgument->names = new \ArrayObject();
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
$defaultArgument->names[$index] = $parameter->name;
|
||||
|
||||
if (\array_key_exists($parameter->name, $arguments)) {
|
||||
$arguments[$index] = $arguments[$parameter->name];
|
||||
unset($arguments[$parameter->name]);
|
||||
}
|
||||
if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = ProxyHelper::exportType($parameter, true);
|
||||
$target = null;
|
||||
$name = Target::parseName($parameter, $target);
|
||||
$target = $target ? [$target] : [];
|
||||
$currentId = $this->currentId;
|
||||
|
||||
$getValue = function () use ($type, $parameter, $class, $method, $name, $target, $defaultArgument, $currentId) {
|
||||
if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $name, $target), false)) {
|
||||
$failureMessage = $this->createTypeNotFoundMessageCallback($ref, \sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $currentId ? $class.'::'.$method : $method));
|
||||
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$value = $defaultArgument->withValue($parameter);
|
||||
} elseif (!$parameter->allowsNull()) {
|
||||
throw new AutowiringFailedException($currentId, $failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
|
||||
if ($checkAttributes) {
|
||||
$attributes = array_merge($parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF), $parameter->getAttributes(Lazy::class, \ReflectionAttribute::IS_INSTANCEOF));
|
||||
|
||||
if (1 < \count($attributes)) {
|
||||
throw new AutowiringFailedException($this->currentId, 'Using both attributes #[Lazy] and #[Autowire] on an argument is not allowed; use the "lazy" parameter of #[Autowire] instead.');
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$attribute = $attribute->newInstance();
|
||||
$value = $attribute instanceof Autowire ? $attribute->value : null;
|
||||
|
||||
if (\is_string($value) && str_starts_with($value, '%env(') && str_ends_with($value, ')%')) {
|
||||
if ($parameter->getType() instanceof \ReflectionNamedType && 'bool' === $parameter->getType()->getName() && !str_starts_with($value, '%env(bool:')) {
|
||||
$attribute = new Autowire(substr_replace($value, 'bool:', 5, 0));
|
||||
}
|
||||
if ($parameter->isDefaultValueAvailable() && $parameter->allowsNull() && null === $parameter->getDefaultValue() && !preg_match('/(^|:)default:/', $value)) {
|
||||
$attribute = new Autowire(substr_replace($value, 'default::', 5, 0));
|
||||
}
|
||||
}
|
||||
|
||||
$invalidBehavior = $parameter->allowsNull() ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
|
||||
try {
|
||||
$value = $this->processValue(new TypedReference($type ?: '?', $type ?: 'mixed', $invalidBehavior, $name, [$attribute, ...$target]));
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
throw new AutowiringFailedException($this->currentId, $e->getMessage(), 0, $e);
|
||||
}
|
||||
$arguments[$index] = clone $defaultArgument;
|
||||
$arguments[$index]->value = $parameter->getDefaultValue();
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if ($attribute instanceof AutowireInline) {
|
||||
$value = $attribute->buildDefinition($value, $type, $parameter);
|
||||
$value = $this->doProcessValue($value);
|
||||
} elseif ($lazy = $attribute->lazy) {
|
||||
$value ??= $getValue();
|
||||
|
||||
if (!\is_array($lazy)) {
|
||||
if (str_contains($type, '|')) {
|
||||
throw new AutowiringFailedException($this->currentId, \sprintf('Cannot use #[Autowire] with option "lazy: true" on union types for service "%s"; set the option to the interface(s) that should be proxied instead.', $this->currentId));
|
||||
}
|
||||
$lazy = str_contains($type, '&') ? explode('&', $type) : [];
|
||||
}
|
||||
|
||||
$proxyType = $lazy ? $type : $this->resolveProxyType($type, $value);
|
||||
$definition = (new Definition($proxyType))
|
||||
->setFactory('current')
|
||||
->setArguments([[$value]])
|
||||
->setLazy(true);
|
||||
|
||||
if ($lazy) {
|
||||
if (!$this->container->getReflectionClass($proxyType, false)) {
|
||||
$definition->setClass('object');
|
||||
}
|
||||
foreach ($lazy as $v) {
|
||||
$definition->addTag('proxy', ['interface' => $v]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->getClass() !== (string) $value || $definition->getTag('proxy')) {
|
||||
$value .= '.'.$this->container->hash([$definition->getClass(), $definition->getTag('proxy')]);
|
||||
}
|
||||
$this->container->setDefinition($value = '.lazy.'.$value, $definition);
|
||||
$value = new Reference($value);
|
||||
}
|
||||
$arguments[$index] = $value;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
foreach ($parameter->getAttributes(AutowireDecorated::class) as $attribute) {
|
||||
$arguments[$index] = $this->processValue($attribute->newInstance());
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$type) {
|
||||
if (isset($arguments[$index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// no default value? Then fail
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
// For core classes, isDefaultValueAvailable() can
|
||||
// be false when isOptional() returns true. If the
|
||||
// argument *is* optional, allow it to be missing
|
||||
if ($parameter->isOptional()) {
|
||||
--$index;
|
||||
break;
|
||||
}
|
||||
$type = ProxyHelper::exportType($parameter);
|
||||
$type = $type ? \sprintf('is type-hinted "%s"', preg_replace('/(^|[(|&])\\\\|^\?\\\\?/', '\1', $type)) : 'has no type-hint';
|
||||
|
||||
throw new AutowiringFailedException($this->currentId, \sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type));
|
||||
}
|
||||
|
||||
// specifically pass the default value
|
||||
$arguments[$index] = $defaultArgument->withValue($parameter);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->decoratedClass && is_a($this->decoratedClass, $type, true)) {
|
||||
if ($this->restorePreviousValue) {
|
||||
// The inner service is injected only if there is only 1 argument matching the type of the decorated class
|
||||
// across all arguments of all autowired methods.
|
||||
// If a second matching argument is found, the default behavior is restored.
|
||||
($this->restorePreviousValue)();
|
||||
$this->decoratedClass = $this->restorePreviousValue = null; // Prevent further checks
|
||||
} else {
|
||||
$arguments[$index] = new TypedReference($this->decoratedId, $this->decoratedClass);
|
||||
$argumentAtIndex = &$arguments[$index];
|
||||
$this->restorePreviousValue = static function () use (&$argumentAtIndex, $getValue) {
|
||||
$argumentAtIndex = $getValue();
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$arguments[$index] = $getValue();
|
||||
}
|
||||
|
||||
if ($parameters && !isset($arguments[++$index])) {
|
||||
while (0 <= --$index) {
|
||||
if (!$arguments[$index] instanceof $defaultArgument) {
|
||||
break;
|
||||
}
|
||||
unset($arguments[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
// it's possible index 1 was set, then index 0, then 2, etc
|
||||
// make sure that we re-order so they're injected as expected
|
||||
ksort($arguments, \SORT_NATURAL);
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the service matching the given type, if any.
|
||||
*/
|
||||
private function getAutowiredReference(TypedReference $reference, bool $filterType): ?TypedReference
|
||||
{
|
||||
$this->lastFailure = null;
|
||||
$type = $reference->getType();
|
||||
|
||||
if ($type !== (string) $reference) {
|
||||
return $reference;
|
||||
}
|
||||
|
||||
if ($filterType && false !== $m = strpbrk($type, '&|')) {
|
||||
$types = array_diff(explode($m[0], $type), ['int', 'string', 'array', 'bool', 'float', 'iterable', 'object', 'callable', 'null']);
|
||||
|
||||
sort($types);
|
||||
|
||||
$type = implode($m[0], $types);
|
||||
}
|
||||
|
||||
$name = $target = (array_filter($reference->getAttributes(), static fn ($a) => $a instanceof Target)[0] ?? null)?->name;
|
||||
|
||||
if (null !== $name ??= $reference->getName()) {
|
||||
if (null !== ($alias = $this->getCombinedAlias($type, $name, $target)) && $this->canDefinitionBeAutowired($alias)) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
if ($this->container->has($name) && $this->canDefinitionBeAutowired($name)) {
|
||||
foreach ($this->container->getAliases() as $id => $alias) {
|
||||
if ($name === (string) $alias && str_starts_with($id, $type.' $')) {
|
||||
return new TypedReference($name, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $target) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== ($alias = $this->getCombinedAlias($type)) && $this->canDefinitionBeAutowired($alias)) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function canDefinitionBeAutowired(string $id): bool
|
||||
{
|
||||
$definition = $this->container->findDefinition($id);
|
||||
|
||||
return !$definition->isAbstract() && !$definition->hasTag('container.excluded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the list of available types.
|
||||
*/
|
||||
private function populateAvailableTypes(ContainerBuilder $container): void
|
||||
{
|
||||
$this->types = [];
|
||||
$this->ambiguousServiceTypes = [];
|
||||
$this->autowiringAliases = [];
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$this->populateAvailableType($container, $id, $definition);
|
||||
}
|
||||
|
||||
$prev = null;
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$this->populateAutowiringAlias($id, $prev);
|
||||
$prev = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the list of available types for a given definition.
|
||||
*/
|
||||
private function populateAvailableType(ContainerBuilder $container, string $id, Definition $definition): void
|
||||
{
|
||||
// Never use abstract services
|
||||
if ($definition->isAbstract()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('' === $id || '.' === $id[0] || $definition->isDeprecated() || !$reflectionClass = $container->getReflectionClass($definition->getClass(), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
|
||||
$this->set($reflectionInterface->name, $id);
|
||||
}
|
||||
|
||||
do {
|
||||
$this->set($reflectionClass->name, $id);
|
||||
} while ($reflectionClass = $reflectionClass->getParentClass());
|
||||
|
||||
$this->populateAutowiringAlias($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a type and a service id if applicable.
|
||||
*/
|
||||
private function set(string $type, string $id): void
|
||||
{
|
||||
// is this already a type/class that is known to match multiple services?
|
||||
if (isset($this->ambiguousServiceTypes[$type])) {
|
||||
$this->ambiguousServiceTypes[$type][] = $id;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check to make sure the type doesn't match multiple services
|
||||
if (!isset($this->types[$type]) || $this->types[$type] === $id) {
|
||||
$this->types[$type] = $id;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// keep an array of all services matching this type
|
||||
if (!isset($this->ambiguousServiceTypes[$type])) {
|
||||
$this->ambiguousServiceTypes[$type] = [$this->types[$type]];
|
||||
unset($this->types[$type]);
|
||||
}
|
||||
$this->ambiguousServiceTypes[$type][] = $id;
|
||||
}
|
||||
|
||||
private function createTypeNotFoundMessageCallback(TypedReference $reference, string $label): \Closure
|
||||
{
|
||||
if (!isset($this->typesClone->container)) {
|
||||
$this->typesClone->container = new ContainerBuilder($this->container->getParameterBag());
|
||||
$this->typesClone->container->setAliases($this->container->getAliases());
|
||||
$this->typesClone->container->setDefinitions($this->container->getDefinitions());
|
||||
$this->typesClone->container->setResourceTracking(false);
|
||||
}
|
||||
$currentId = $this->currentId;
|
||||
|
||||
return (fn () => $this->createTypeNotFoundMessage($reference, $label, $currentId))->bindTo($this->typesClone);
|
||||
}
|
||||
|
||||
private function createTypeNotFoundMessage(TypedReference $reference, string $label, string $currentId): string
|
||||
{
|
||||
$type = $reference->getType();
|
||||
|
||||
$i = null;
|
||||
$namespace = $type;
|
||||
do {
|
||||
$namespace = substr($namespace, 0, $i);
|
||||
|
||||
if ($this->container->hasDefinition($namespace) && $tag = $this->container->getDefinition($namespace)->getTag('container.excluded')) {
|
||||
return \sprintf('Cannot autowire service "%s": %s needs an instance of "%s" but this type has been excluded %s.', $currentId, $label, $type, $tag[0]['source'] ?? 'from autowiring');
|
||||
}
|
||||
} while (false !== $i = strrpos($namespace, '\\'));
|
||||
|
||||
if (!$r = $this->container->getReflectionClass($type, false)) {
|
||||
// either $type does not exist or a parent class does not exist
|
||||
try {
|
||||
if (class_exists(ClassExistenceResource::class)) {
|
||||
$resource = new ClassExistenceResource($type, false);
|
||||
// isFresh() will explode ONLY if a parent class/trait does not exist
|
||||
$resource->isFresh(0);
|
||||
$parentMsg = false;
|
||||
} else {
|
||||
$parentMsg = "couldn't be loaded. Either it was not found or it is missing a parent class or a trait";
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
$parentMsg = \sprintf('is missing a parent class (%s)', $e->getMessage());
|
||||
}
|
||||
|
||||
$message = \sprintf('has type "%s" but this class %s.', $type, $parentMsg ?: 'was not found');
|
||||
} else {
|
||||
$alternatives = $this->createTypeAlternatives($this->container, $reference);
|
||||
|
||||
if (null !== $target = (array_filter($reference->getAttributes(), static fn ($a) => $a instanceof Target)[0] ?? null)) {
|
||||
$target = null !== $target->name ? "('{$target->name}')" : '';
|
||||
$message = \sprintf('has "#[Target%s]" but no such target exists.%s', $target, $alternatives);
|
||||
} else {
|
||||
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
|
||||
$message = \sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $alternatives);
|
||||
}
|
||||
|
||||
if ($r->isInterface() && !$alternatives) {
|
||||
$message .= ' Did you create an instantiable class that implements this interface?';
|
||||
}
|
||||
}
|
||||
|
||||
$message = \sprintf('Cannot autowire service "%s": %s %s', $currentId, $label, $message);
|
||||
|
||||
if (null !== $this->lastFailure) {
|
||||
$message = $this->lastFailure."\n".$message;
|
||||
$this->lastFailure = null;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function createTypeAlternatives(ContainerBuilder $container, TypedReference $reference): string
|
||||
{
|
||||
// try suggesting available aliases first
|
||||
if ($message = $this->getAliasesSuggestionForType($container, $type = $reference->getType())) {
|
||||
return ' '.$message;
|
||||
}
|
||||
if (!isset($this->ambiguousServiceTypes)) {
|
||||
$this->populateAvailableTypes($container);
|
||||
}
|
||||
|
||||
$servicesAndAliases = $container->getServiceIds();
|
||||
$autowiringAliases = $this->autowiringAliases[$type] ?? [];
|
||||
unset($autowiringAliases['']);
|
||||
|
||||
if ($autowiringAliases) {
|
||||
return \sprintf(' Did you mean to target%s "%s" instead?', 1 < \count($autowiringAliases) ? ' one of' : '', implode('", "', $autowiringAliases));
|
||||
}
|
||||
|
||||
if (!$container->has($type) && false !== $key = array_search(strtolower($type), array_map('strtolower', $servicesAndAliases))) {
|
||||
return \sprintf(' Did you mean "%s"?', $servicesAndAliases[$key]);
|
||||
} elseif (isset($this->ambiguousServiceTypes[$type])) {
|
||||
$message = \sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type]));
|
||||
} elseif (isset($this->types[$type])) {
|
||||
$message = \sprintf('the existing "%s" service', $this->types[$type]);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
return \sprintf(' You should maybe alias this %s to %s.', class_exists($type, false) ? 'class' : 'interface', $message);
|
||||
}
|
||||
|
||||
private function getAliasesSuggestionForType(ContainerBuilder $container, string $type): ?string
|
||||
{
|
||||
$aliases = [];
|
||||
foreach (class_parents($type) + class_implements($type) as $parent) {
|
||||
if ($container->has($parent) && $this->canDefinitionBeAutowired($parent)) {
|
||||
$aliases[] = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 < $len = \count($aliases)) {
|
||||
$message = 'Try changing the type-hint to one of its parents: ';
|
||||
for ($i = 0, --$len; $i < $len; ++$i) {
|
||||
$message .= \sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
|
||||
}
|
||||
|
||||
return $message.\sprintf('or %s "%s".', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
|
||||
}
|
||||
|
||||
if ($aliases) {
|
||||
return \sprintf('Try changing the type-hint to "%s" instead.', $aliases[0]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function populateAutowiringAlias(string $id, ?string $target = null): void
|
||||
{
|
||||
if (!preg_match('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))^((?&V)(?:\\\\(?&V))*+)(?: \$((?&V)))?$/', $id, $m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $m[2];
|
||||
$name = $m[3] ?? '';
|
||||
|
||||
if (class_exists($type, false) || interface_exists($type, false)) {
|
||||
if (null !== $target && str_starts_with($target, '.'.$type.' $')) {
|
||||
$name = substr($target, \strlen($type) + 3);
|
||||
}
|
||||
|
||||
$this->autowiringAliases[$type][$name] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
private function getCombinedAlias(string $type, ?string $name = null, ?string $target = null): ?string
|
||||
{
|
||||
$prefix = $target && $name ? '.' : '';
|
||||
$suffix = $name ? ' $'.($target ?? $name) : '';
|
||||
$parsedName = $target ?? ($name ? (new Target($name))->getParsedName() : null);
|
||||
|
||||
if ($this->container->has($alias = $prefix.$type.$suffix) && $this->canDefinitionBeAutowired($alias)) {
|
||||
return $alias;
|
||||
}
|
||||
|
||||
if (str_contains($type, '&')) {
|
||||
$types = explode('&', $type);
|
||||
} elseif (str_contains($type, '|')) {
|
||||
$types = explode('|', $type);
|
||||
} else {
|
||||
return $prefix || $name !== $parsedName && ($name = $parsedName) ? $this->getCombinedAlias($type, $name) : null;
|
||||
}
|
||||
|
||||
$alias = null;
|
||||
|
||||
foreach ($types as $type) {
|
||||
if (!$this->container->hasAlias($prefix.$type.$suffix)) {
|
||||
return $prefix || $name !== $parsedName && ($name = $parsedName) ? $this->getCombinedAlias($type, $name) : null;
|
||||
}
|
||||
|
||||
if (null === $alias) {
|
||||
$alias = (string) $this->container->getAlias($prefix.$type.$suffix);
|
||||
} elseif ((string) $this->container->getAlias($prefix.$type.$suffix) !== $alias) {
|
||||
return $prefix || $name !== $parsedName && ($name = $parsedName) ? $this->getCombinedAlias($type, $name) : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the class name that should be proxied for a lazy service.
|
||||
*
|
||||
* @param string $originalType The original parameter type-hint (e.g., the interface)
|
||||
* @param string $serviceId The service ID the type-hint resolved to (e.g., the alias)
|
||||
*/
|
||||
private function resolveProxyType(string $originalType, string $serviceId): string
|
||||
{
|
||||
if (!$this->container->has($serviceId)) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
$resolvedType = $this->container->findDefinition($serviceId)->getClass();
|
||||
$resolvedType = $this->container->getParameterBag()->resolveValue($resolvedType);
|
||||
|
||||
if (!$resolvedType || !$this->container->getReflectionClass($resolvedType, false)) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
if (\PHP_VERSION_ID < 80400 && $this->container->getReflectionClass($resolvedType, false)->isFinal()) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
return $resolvedType;
|
||||
}
|
||||
}
|
||||
94
backend/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php
vendored
Normal file
94
backend/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
/**
|
||||
* Looks for definitions with autowiring enabled and registers their corresponding "#[Required]" methods as setters.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class AutowireRequiredMethodsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||
return $value;
|
||||
}
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$alreadyCalledMethods = [];
|
||||
$withers = [];
|
||||
|
||||
foreach ($value->getMethodCalls() as [$method]) {
|
||||
$alreadyCalledMethods[strtolower($method)] = true;
|
||||
}
|
||||
|
||||
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
|
||||
$r = $reflectionMethod;
|
||||
|
||||
if ($r->isConstructor() || isset($alreadyCalledMethods[strtolower($r->name)])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if ($r->getAttributes(Required::class)) {
|
||||
if ($this->isWither($r, $r->getDocComment() ?: '')) {
|
||||
$withers[] = [$r->name, [], true];
|
||||
} else {
|
||||
$value->addMethodCall($r->name, []);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!$r->hasPrototype()) {
|
||||
break;
|
||||
}
|
||||
$r = $r->getPrototype();
|
||||
}
|
||||
}
|
||||
|
||||
if ($withers) {
|
||||
// Prepend withers to prevent creating circular loops
|
||||
$setters = $value->getMethodCalls();
|
||||
$value->setMethodCalls($withers);
|
||||
foreach ($setters as $call) {
|
||||
$value->addMethodCall($call[0], $call[1], $call[2] ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function isWither(\ReflectionMethod $reflectionMethod, string $doc): bool
|
||||
{
|
||||
$match = preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++(static|\$this)[\s\*]#i', $doc, $matches);
|
||||
if ($match && 'static' === $matches[1]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($match && '$this' === $matches[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$reflectionType = $reflectionMethod->hasReturnType() ? $reflectionMethod->getReturnType() : null;
|
||||
|
||||
return $reflectionType instanceof \ReflectionNamedType && 'static' === $reflectionType->getName();
|
||||
}
|
||||
}
|
||||
65
backend/vendor/symfony/dependency-injection/Compiler/AutowireRequiredPropertiesPass.php
vendored
Normal file
65
backend/vendor/symfony/dependency-injection/Compiler/AutowireRequiredPropertiesPass.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
/**
|
||||
* Looks for definitions with autowiring enabled and registers their corresponding "#[Required]" properties.
|
||||
*
|
||||
* @author Sebastien Morel (Plopix) <morel.seb@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class AutowireRequiredPropertiesPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||
return $value;
|
||||
}
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$properties = $value->getProperties();
|
||||
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
|
||||
if (!($type = $reflectionProperty->getType()) instanceof \ReflectionNamedType) {
|
||||
continue;
|
||||
}
|
||||
if (!$reflectionProperty->getAttributes(Required::class)) {
|
||||
continue;
|
||||
}
|
||||
if (\array_key_exists($name = $reflectionProperty->getName(), $properties)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $type->getName();
|
||||
$value->setProperty($name, new TypedReference($type, $type, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name, array_map(static fn ($a) => $a->newInstance(), array_merge(
|
||||
$reflectionProperty->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF),
|
||||
$reflectionProperty->getAttributes(AutowireDecorated::class),
|
||||
$reflectionProperty->getAttributes(Target::class),
|
||||
))));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
51
backend/vendor/symfony/dependency-injection/Compiler/CheckAliasValidityPass.php
vendored
Normal file
51
backend/vendor/symfony/dependency-injection/Compiler/CheckAliasValidityPass.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* This pass validates aliases, it provides the following checks:
|
||||
*
|
||||
* - An alias which happens to be an interface must resolve to a service implementing this interface. This ensures injecting the aliased interface won't cause a type error at runtime.
|
||||
*/
|
||||
class CheckAliasValidityPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
try {
|
||||
if (!$container->hasDefinition((string) $alias)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$target = $container->getDefinition((string) $alias);
|
||||
if (null === $target->getClass() || null !== $target->getFactory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflection = $container->getReflectionClass($id);
|
||||
if (null === $reflection || !$reflection->isInterface()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$targetReflection = $container->getReflectionClass($target->getClass());
|
||||
if (null !== $targetReflection && !$targetReflection->implementsInterface($id)) {
|
||||
throw new RuntimeException(\sprintf('Invalid alias definition: alias "%s" is referencing class "%s" but this class does not implement "%s". Because this alias is an interface, "%s" must implement "%s".', $id, $target->getClass(), $id, $target->getClass(), $id));
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
backend/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php
vendored
Normal file
116
backend/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Checks if arguments of methods are properly configured.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class CheckArgumentsValidityPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
public function __construct(
|
||||
private bool $throwExceptions = true,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$hasNamedArgs = false;
|
||||
foreach ($value->getArguments() as $k => $v) {
|
||||
if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
|
||||
$hasNamedArgs = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($k !== $i++) {
|
||||
if (!\is_int($k)) {
|
||||
$msg = \sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = \sprintf('Invalid constructor argument %d for service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $this->currentId, $i);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasNamedArgs) {
|
||||
$msg = \sprintf('Invalid constructor argument for service "%s": cannot use positional argument after named argument. Check your service definition.', $this->currentId);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($value->getMethodCalls() as $methodCall) {
|
||||
$i = 0;
|
||||
$hasNamedArgs = false;
|
||||
foreach ($methodCall[1] as $k => $v) {
|
||||
if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
|
||||
$hasNamedArgs = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($k !== $i++) {
|
||||
if (!\is_int($k)) {
|
||||
$msg = \sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = \sprintf('Invalid argument %d for method call "%s" of service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $methodCall[0], $this->currentId, $i);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasNamedArgs) {
|
||||
$msg = \sprintf('Invalid argument for method call "%s" of service "%s": cannot use positional argument after named argument. Check your service definition.', $methodCall[0], $this->currentId);
|
||||
$value->addError($msg);
|
||||
if ($this->throwExceptions) {
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
93
backend/vendor/symfony/dependency-injection/Compiler/CheckCircularReferencesPass.php
vendored
Normal file
93
backend/vendor/symfony/dependency-injection/Compiler/CheckCircularReferencesPass.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
|
||||
/**
|
||||
* Checks your services for circular references.
|
||||
*
|
||||
* References from method calls are ignored since we might be able to resolve
|
||||
* these references depending on the order in which services are called.
|
||||
*
|
||||
* Circular reference from method calls will only be detected at run-time.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckCircularReferencesPass implements CompilerPassInterface
|
||||
{
|
||||
private array $currentPath;
|
||||
private array $checkedNodes;
|
||||
private array $checkedLazyNodes;
|
||||
|
||||
/**
|
||||
* Checks the ContainerBuilder object for circular references.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
|
||||
$this->checkedNodes = [];
|
||||
foreach ($graph->getNodes() as $id => $node) {
|
||||
$this->currentPath = [$id];
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for circular references.
|
||||
*
|
||||
* @param ServiceReferenceGraphEdge[] $edges An array of Edges
|
||||
*
|
||||
* @throws ServiceCircularReferenceException when a circular reference is found
|
||||
*/
|
||||
private function checkOutEdges(array $edges): void
|
||||
{
|
||||
foreach ($edges as $edge) {
|
||||
$node = $edge->getDestNode();
|
||||
$id = $node->getId();
|
||||
|
||||
if (!empty($this->checkedNodes[$id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isLeaf = (bool) $node->getValue();
|
||||
$isConcrete = !$edge->isLazy() && !$edge->isWeak();
|
||||
|
||||
// Skip already checked lazy services if they are still lazy. Will not gain any new information.
|
||||
if (!empty($this->checkedLazyNodes[$id]) && (!$isLeaf || !$isConcrete)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process concrete references, otherwise defer check circular references for lazy edges.
|
||||
if (!$isLeaf || $isConcrete) {
|
||||
$searchKey = array_search($id, $this->currentPath);
|
||||
$this->currentPath[] = $id;
|
||||
|
||||
if (false !== $searchKey) {
|
||||
throw new ServiceCircularReferenceException($id, \array_slice($this->currentPath, $searchKey));
|
||||
}
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
|
||||
$this->checkedNodes[$id] = true;
|
||||
unset($this->checkedLazyNodes[$id]);
|
||||
} else {
|
||||
$this->checkedLazyNodes[$id] = true;
|
||||
}
|
||||
|
||||
array_pop($this->currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
backend/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php
vendored
Normal file
102
backend/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Loader\FileLoader;
|
||||
|
||||
/**
|
||||
* This pass validates each definition individually only taking the information
|
||||
* into account which is contained in the definition itself.
|
||||
*
|
||||
* Later passes can rely on the following, and specifically do not need to
|
||||
* perform these checks themselves:
|
||||
*
|
||||
* - non synthetic, non abstract services always have a class set
|
||||
* - synthetic services are always public
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckDefinitionValidityPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Processes the ContainerBuilder to validate the Definition.
|
||||
*
|
||||
* @throws RuntimeException When the Definition is invalid
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->hasErrors()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// synthetic service is public
|
||||
if ($definition->isSynthetic() && !$definition->isPublic()) {
|
||||
throw new RuntimeException(\sprintf('A synthetic service ("%s") must be public.', $id));
|
||||
}
|
||||
|
||||
// non-synthetic, non-abstract service has class
|
||||
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && !$definition->hasTag('container.service_locator') && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) {
|
||||
if ($definition->getFactory()) {
|
||||
throw new RuntimeException(\sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id));
|
||||
}
|
||||
if (class_exists($id) || interface_exists($id, false)) {
|
||||
if (str_starts_with($id, '\\') && 1 < substr_count($id, '\\')) {
|
||||
throw new RuntimeException(\sprintf('The definition for "%s" has no class attribute, and appears to reference a class or interface. Please specify the class attribute explicitly or remove the leading backslash by renaming the service to "%s" to get rid of this error.', $id, substr($id, 1)));
|
||||
}
|
||||
|
||||
throw new RuntimeException(\sprintf('The definition for "%s" has no class attribute, and appears to reference a class or interface in the global namespace. Leaving out the "class" attribute is only allowed for namespaced classes. Please specify the class attribute explicitly to get rid of this error.', $id));
|
||||
}
|
||||
|
||||
throw new RuntimeException(\sprintf('The definition for "%s" has no class. If you intend to inject this service dynamically at runtime, please mark it as synthetic=true. If this is an abstract definition solely used by child definitions, please add abstract=true, otherwise specify a class to get rid of this error.', $id));
|
||||
}
|
||||
|
||||
// tag attribute values must be scalars
|
||||
foreach ($definition->getTags() as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
$this->validateAttributes($id, $name, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->isPublic()) {
|
||||
$resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs);
|
||||
if (null !== $usedEnvs) {
|
||||
throw new EnvParameterException([$resolvedId], null, 'A service name ("%s") cannot contain dynamic values.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($alias->isPublic()) {
|
||||
$resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs);
|
||||
if (null !== $usedEnvs) {
|
||||
throw new EnvParameterException([$resolvedId], null, 'An alias name ("%s") cannot contain dynamic values.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateAttributes(string $id, string $tag, array $attributes, array $path = []): void
|
||||
{
|
||||
foreach ($attributes as $name => $value) {
|
||||
if (\is_array($value)) {
|
||||
$this->validateAttributes($id, $tag, $value, [...$path, $name]);
|
||||
} elseif (!\is_scalar($value) && null !== $value) {
|
||||
$name = implode('.', [...$path, $name]);
|
||||
throw new RuntimeException(\sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s".', $id, $tag, $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Checks that all references are pointing to a valid service.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckExceptionOnInvalidReferenceBehaviorPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $serviceLocatorContextIds = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->serviceLocatorContextIds = [];
|
||||
foreach ($container->findTaggedServiceIds('container.service_locator_context') as $id => $tags) {
|
||||
$this->serviceLocatorContextIds[$id] = $tags[0]['id'];
|
||||
$container->getDefinition($id)->clearTag('container.service_locator_context');
|
||||
}
|
||||
|
||||
try {
|
||||
parent::process($container);
|
||||
} finally {
|
||||
$this->serviceLocatorContextIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Reference) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $value->getInvalidBehavior() || $this->container->has((string) $value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$currentId = $this->currentId;
|
||||
$graph = $this->container->getCompiler()->getServiceReferenceGraph();
|
||||
|
||||
if (isset($this->serviceLocatorContextIds[$currentId])) {
|
||||
$currentId = $this->serviceLocatorContextIds[$currentId];
|
||||
$locator = $this->container->getDefinition($this->currentId)->getFactory()[0];
|
||||
$this->throwServiceNotFoundException($value, $currentId, $locator->getArgument(0));
|
||||
}
|
||||
|
||||
if ('.' === $currentId[0] && $graph->hasNode($currentId)) {
|
||||
foreach ($graph->getNode($currentId)->getInEdges() as $edge) {
|
||||
if (!$edge->getValue() instanceof Reference || ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $edge->getValue()->getInvalidBehavior()) {
|
||||
continue;
|
||||
}
|
||||
$sourceId = $edge->getSourceNode()->getId();
|
||||
|
||||
if ('.' !== $sourceId[0]) {
|
||||
$currentId = $sourceId;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($this->serviceLocatorContextIds[$sourceId])) {
|
||||
$currentId = $this->serviceLocatorContextIds[$sourceId];
|
||||
$locator = $this->container->getDefinition($this->currentId);
|
||||
$this->throwServiceNotFoundException($value, $currentId, $locator->getArgument(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->throwServiceNotFoundException($value, $currentId, $value);
|
||||
}
|
||||
|
||||
private function throwServiceNotFoundException(Reference $ref, string $sourceId, mixed $value): void
|
||||
{
|
||||
$id = (string) $ref;
|
||||
$alternatives = [];
|
||||
foreach ($this->container->getServiceIds() as $knownId) {
|
||||
if ('' === $knownId || '.' === $knownId[0] || $knownId === $this->currentId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lev = levenshtein($id, $knownId);
|
||||
if ($lev <= \strlen($id) / 3 || str_contains($knownId, $id)) {
|
||||
$alternatives[] = $knownId;
|
||||
}
|
||||
}
|
||||
|
||||
$pass = new class extends AbstractRecursivePass {
|
||||
public Reference $ref;
|
||||
public string $sourceId;
|
||||
public array $alternatives;
|
||||
|
||||
public function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($this->ref !== $value) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
$sourceId = $this->sourceId;
|
||||
if (null !== $this->currentId && $this->currentId !== (string) $value) {
|
||||
$sourceId = $this->currentId.'" in the container provided to "'.$sourceId;
|
||||
}
|
||||
|
||||
throw new ServiceNotFoundException((string) $value, $sourceId, null, $this->alternatives);
|
||||
}
|
||||
};
|
||||
$pass->ref = $ref;
|
||||
$pass->sourceId = $sourceId;
|
||||
$pass->alternatives = $alternatives;
|
||||
|
||||
$pass->processValue($value, true);
|
||||
}
|
||||
}
|
||||
45
backend/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php
vendored
Normal file
45
backend/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Checks the validity of references.
|
||||
*
|
||||
* The following checks are performed by this pass:
|
||||
* - target definitions are not abstract
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckReferenceValidityPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($isRoot && $value instanceof Definition && ($value->isSynthetic() || $value->isAbstract())) {
|
||||
return $value;
|
||||
}
|
||||
if ($value instanceof Reference && $this->container->hasDefinition((string) $value)) {
|
||||
$targetDefinition = $this->container->getDefinition((string) $value);
|
||||
|
||||
if ($targetDefinition->isAbstract()) {
|
||||
throw new RuntimeException(\sprintf('The definition "%s" has a reference to an abstract definition "%s". Abstract definitions cannot be the target of references.', $this->currentId, $value));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
332
backend/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php
vendored
Normal file
332
backend/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\ExpressionLanguage;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
/**
|
||||
* Checks whether injected parameters are compatible with type declarations.
|
||||
*
|
||||
* This pass should be run after all optimization passes.
|
||||
*
|
||||
* It can be added either:
|
||||
* * before removing passes to check all services even if they are not currently used,
|
||||
* * after removing passes to check only services are used in the app.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Julien Maulny <jmaulny@darkmira.fr>
|
||||
*/
|
||||
final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private const SCALAR_TYPES = [
|
||||
'int' => true,
|
||||
'float' => true,
|
||||
'bool' => true,
|
||||
'string' => true,
|
||||
];
|
||||
|
||||
private const BUILTIN_TYPES = [
|
||||
'array' => true,
|
||||
'bool' => true,
|
||||
'callable' => true,
|
||||
'float' => true,
|
||||
'int' => true,
|
||||
'iterable' => true,
|
||||
'object' => true,
|
||||
'string' => true,
|
||||
];
|
||||
|
||||
private ExpressionLanguage $expressionLanguage;
|
||||
|
||||
/**
|
||||
* @param bool $autoload Whether services who's class in not loaded should be checked or not.
|
||||
* Defaults to false to save loading code during compilation.
|
||||
* @param array $skippedIds An array indexed by the service ids to skip
|
||||
*/
|
||||
public function __construct(
|
||||
private bool $autoload = false,
|
||||
private array $skippedIds = [],
|
||||
) {
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (isset($this->skippedIds[$this->currentId ?? ''])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition || $value->hasErrors() || $value->isDeprecated()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if (!$this->autoload) {
|
||||
if (!$class = $value->getClass()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
if (!class_exists($class, false) && !interface_exists($class, false)) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
|
||||
if (ServiceLocator::class === $value->getClass()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if ($constructor = $this->getConstructor($value, false)) {
|
||||
$this->checkTypeDeclarations($value, $constructor, $value->getArguments());
|
||||
}
|
||||
|
||||
foreach ($value->getMethodCalls() as $methodCall) {
|
||||
try {
|
||||
$reflectionMethod = $this->getReflectionMethod($value, $methodCall[0]);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($value->getFactory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->checkTypeDeclarations($value, $reflectionMethod, $methodCall[1]);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException When not enough parameters are defined for the method
|
||||
*/
|
||||
private function checkTypeDeclarations(Definition $checkedDefinition, \ReflectionFunctionAbstract $reflectionFunction, array $values): void
|
||||
{
|
||||
$numberOfRequiredParameters = $reflectionFunction->getNumberOfRequiredParameters();
|
||||
|
||||
if (\count($values) < $numberOfRequiredParameters) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed.', $this->currentId, $reflectionFunction->class, $reflectionFunction->name, $numberOfRequiredParameters, \count($values)));
|
||||
}
|
||||
|
||||
$reflectionParameters = $reflectionFunction->getParameters();
|
||||
$checksCount = min($reflectionFunction->getNumberOfParameters(), \count($values));
|
||||
|
||||
$envPlaceholderUniquePrefix = $this->container->getParameterBag() instanceof EnvPlaceholderParameterBag ? $this->container->getParameterBag()->getEnvPlaceholderUniquePrefix() : null;
|
||||
|
||||
for ($i = 0; $i < $checksCount; ++$i) {
|
||||
$p = $reflectionParameters[$i];
|
||||
if (!$p->hasType() || $p->isVariadic()) {
|
||||
continue;
|
||||
}
|
||||
$key = $i;
|
||||
if (\array_key_exists($p->name, $values)) {
|
||||
$key = $p->name;
|
||||
} elseif (!\array_key_exists($i, $values)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->checkType($checkedDefinition, $values[$key], $p, $envPlaceholderUniquePrefix);
|
||||
}
|
||||
|
||||
if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) {
|
||||
$variadicParameters = \array_slice($values, $lastParameter->getPosition());
|
||||
|
||||
foreach ($variadicParameters as $variadicParameter) {
|
||||
$this->checkType($checkedDefinition, $variadicParameter, $lastParameter, $envPlaceholderUniquePrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
|
||||
*/
|
||||
private function checkType(Definition $checkedDefinition, mixed $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, ?\ReflectionType $reflectionType = null): void
|
||||
{
|
||||
$reflectionType ??= $parameter->getType();
|
||||
|
||||
if ($reflectionType instanceof \ReflectionUnionType) {
|
||||
foreach ($reflectionType->getTypes() as $t) {
|
||||
try {
|
||||
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t);
|
||||
|
||||
return;
|
||||
} catch (InvalidParameterTypeException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter);
|
||||
}
|
||||
if ($reflectionType instanceof \ReflectionIntersectionType) {
|
||||
foreach ($reflectionType->getTypes() as $t) {
|
||||
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (!$reflectionType instanceof \ReflectionNamedType) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $reflectionType->getName();
|
||||
|
||||
if ($value instanceof Reference) {
|
||||
if (!$this->container->has($value = (string) $value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('service_container' === $value && is_a($type, Container::class, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = $this->container->findDefinition($value);
|
||||
}
|
||||
|
||||
if ('self' === $type) {
|
||||
$type = $parameter->getDeclaringClass()->getName();
|
||||
}
|
||||
|
||||
if ('static' === $type) {
|
||||
$type = $checkedDefinition->getClass();
|
||||
}
|
||||
|
||||
$class = null;
|
||||
|
||||
if ($value instanceof Definition) {
|
||||
if ($value->hasErrors() || $value->getFactory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class = $value->getClass();
|
||||
|
||||
if ($class && isset(self::BUILTIN_TYPES[strtolower($class)])) {
|
||||
$class = strtolower($class);
|
||||
} elseif (!$class || (!$this->autoload && !class_exists($class, false) && !interface_exists($class, false))) {
|
||||
return;
|
||||
}
|
||||
} elseif ($value instanceof Parameter) {
|
||||
$value = $this->container->getParameter($value);
|
||||
} elseif ($value instanceof Expression) {
|
||||
try {
|
||||
$value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this->container]);
|
||||
} catch (\Exception) {
|
||||
// If a service from the expression cannot be fetched from the container, we skip the validation.
|
||||
return;
|
||||
}
|
||||
} elseif (\is_string($value)) {
|
||||
if ('%' === ($value[0] ?? '') && preg_match('/^%([^%]+)%$/', $value, $match)) {
|
||||
$value = $this->container->getParameter(substr($value, 1, -1));
|
||||
}
|
||||
|
||||
if ($envPlaceholderUniquePrefix && \is_string($value) && str_contains($value, 'env_')) {
|
||||
// If the value is an env placeholder that is either mixed with a string or with another env placeholder, then its resolved value will always be a string, so we don't need to resolve it.
|
||||
// We don't need to change the value because it is already a string.
|
||||
if ('' === preg_replace('/'.$envPlaceholderUniquePrefix.'_\w+_[a-f0-9]{32}/U', '', $value, -1, $c) && 1 === $c) {
|
||||
try {
|
||||
$value = $this->container->resolveEnvPlaceholders($value, true);
|
||||
} catch (\Exception) {
|
||||
// If an env placeholder cannot be resolved, we skip the validation.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $value && $parameter->allowsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $class) {
|
||||
if ($value instanceof IteratorArgument) {
|
||||
$class = RewindableGenerator::class;
|
||||
} elseif ($value instanceof ServiceClosureArgument) {
|
||||
$class = \Closure::class;
|
||||
} elseif ($value instanceof ServiceLocatorArgument) {
|
||||
$class = ServiceLocator::class;
|
||||
} elseif (\is_object($value)) {
|
||||
$class = $value::class;
|
||||
} else {
|
||||
$class = \gettype($value);
|
||||
$class = ['integer' => 'int', 'double' => 'float', 'boolean' => 'bool'][$class] ?? $class;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset(self::SCALAR_TYPES[$type]) && isset(self::SCALAR_TYPES[$class])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('string' === $type && is_a($class, \Stringable::class, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('callable' === $type && (\Closure::class === $class || method_exists($class, '__invoke'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('callable' === $type && \is_array($value) && isset($value[0]) && ($value[0] instanceof Reference || $value[0] instanceof Definition || \is_string($value[0]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('iterable' === $type && (\is_array($value) || 'array' === $class || is_subclass_of($class, \Traversable::class))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($type === $class) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('object' === $type && !isset(self::BUILTIN_TYPES[$class])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('mixed' === $type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_a($class, $type, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('false' === $type) {
|
||||
if (false === $value) {
|
||||
return;
|
||||
}
|
||||
} elseif ('true' === $type) {
|
||||
if (true === $value) {
|
||||
return;
|
||||
}
|
||||
} elseif ($reflectionType->isBuiltin()) {
|
||||
$checkFunction = \sprintf('is_%s', $type);
|
||||
if ($checkFunction($value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : get_debug_type($value), $parameter);
|
||||
}
|
||||
|
||||
private function getExpressionLanguage(): ExpressionLanguage
|
||||
{
|
||||
return $this->expressionLanguage ??= new ExpressionLanguage(null, $this->container->getExpressionLanguageProviders());
|
||||
}
|
||||
}
|
||||
97
backend/vendor/symfony/dependency-injection/Compiler/Compiler.php
vendored
Normal file
97
backend/vendor/symfony/dependency-injection/Compiler/Compiler.php
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
|
||||
|
||||
/**
|
||||
* This class is used to remove circular dependencies between individual passes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Compiler
|
||||
{
|
||||
private PassConfig $passConfig;
|
||||
private array $log = [];
|
||||
private ServiceReferenceGraph $serviceReferenceGraph;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->passConfig = new PassConfig();
|
||||
$this->serviceReferenceGraph = new ServiceReferenceGraph();
|
||||
}
|
||||
|
||||
public function getPassConfig(): PassConfig
|
||||
{
|
||||
return $this->passConfig;
|
||||
}
|
||||
|
||||
public function getServiceReferenceGraph(): ServiceReferenceGraph
|
||||
{
|
||||
return $this->serviceReferenceGraph;
|
||||
}
|
||||
|
||||
public function addPass(CompilerPassInterface $pass, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): void
|
||||
{
|
||||
$this->passConfig->addPass($pass, $type, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
public function log(CompilerPassInterface $pass, string $message): void
|
||||
{
|
||||
if (str_contains($message, "\n")) {
|
||||
$message = str_replace("\n", "\n".$pass::class.': ', trim($message));
|
||||
}
|
||||
|
||||
$this->log[] = $pass::class.': '.$message;
|
||||
}
|
||||
|
||||
public function getLog(): array
|
||||
{
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Compiler and process all Passes.
|
||||
*/
|
||||
public function compile(ContainerBuilder $container): void
|
||||
{
|
||||
try {
|
||||
foreach ($this->passConfig->getPasses() as $pass) {
|
||||
$pass->process($container);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$usedEnvs = [];
|
||||
$prev = $e;
|
||||
|
||||
do {
|
||||
$msg = $prev->getMessage();
|
||||
|
||||
if ($msg !== $resolvedMsg = $container->resolveEnvPlaceholders($msg, null, $usedEnvs)) {
|
||||
$r = new \ReflectionProperty($prev, 'message');
|
||||
$r->setValue($prev, $resolvedMsg);
|
||||
}
|
||||
} while ($prev = $prev->getPrevious());
|
||||
|
||||
if ($usedEnvs) {
|
||||
$e = new EnvParameterException($usedEnvs, $e);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
} finally {
|
||||
$this->getServiceReferenceGraph()->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
backend/vendor/symfony/dependency-injection/Compiler/CompilerPassInterface.php
vendored
Normal file
29
backend/vendor/symfony/dependency-injection/Compiler/CompilerPassInterface.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by compilation passes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* You can modify the container here before it is dumped to PHP code.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container);
|
||||
}
|
||||
130
backend/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
vendored
Normal file
130
backend/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Overwrites a service but keeps the overridden one.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Diego Saint Esteben <diego@saintesteben.me>
|
||||
*/
|
||||
class DecoratorServicePass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$definitions = new \SplPriorityQueue();
|
||||
$order = \PHP_INT_MAX;
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if (!$decorated = $definition->getDecoratedService()) {
|
||||
continue;
|
||||
}
|
||||
$definitions->insert([$id, $definition], [$decorated[2], --$order]);
|
||||
}
|
||||
$decoratingDefinitions = [];
|
||||
$decoratedIds = [];
|
||||
|
||||
$tagsToKeep = $container->hasParameter('container.behavior_describing_tags')
|
||||
? $container->getParameter('container.behavior_describing_tags')
|
||||
: ['proxy', 'container.do_not_inline', 'container.service_locator', 'container.service_subscriber', 'container.service_subscriber.locator'];
|
||||
|
||||
foreach ($definitions as [$id, $definition]) {
|
||||
$decoratedService = $definition->getDecoratedService();
|
||||
[$inner, $renamedId] = $decoratedService;
|
||||
$invalidBehavior = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
|
||||
$definition->setDecoratedService(null);
|
||||
|
||||
if (!$renamedId) {
|
||||
$renamedId = $id.'.inner';
|
||||
}
|
||||
|
||||
$decoratedIds[$inner] ??= $renamedId;
|
||||
$this->currentId = $renamedId;
|
||||
$this->processValue($definition);
|
||||
|
||||
$definition->innerServiceId = $renamedId;
|
||||
$definition->decorationOnInvalid = $invalidBehavior;
|
||||
|
||||
// we create a new alias/service for the service we are replacing
|
||||
// to be able to reference it in the new one
|
||||
if ($container->hasAlias($inner)) {
|
||||
$alias = $container->getAlias($inner);
|
||||
$public = $alias->isPublic();
|
||||
$container->setAlias($renamedId, new Alias((string) $alias, false));
|
||||
$decoratedDefinition = $container->findDefinition($alias);
|
||||
} elseif ($container->hasDefinition($inner)) {
|
||||
$decoratedDefinition = $container->getDefinition($inner);
|
||||
$public = $decoratedDefinition->isPublic();
|
||||
$decoratedDefinition->setPublic(false);
|
||||
$container->setDefinition($renamedId, $decoratedDefinition);
|
||||
$decoratingDefinitions[$inner] = $decoratedDefinition;
|
||||
} elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
$container->removeDefinition($id);
|
||||
continue;
|
||||
} elseif (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
$public = $definition->isPublic();
|
||||
$decoratedDefinition = null;
|
||||
} else {
|
||||
throw new ServiceNotFoundException($inner, $id);
|
||||
}
|
||||
|
||||
if ($decoratedDefinition?->isSynthetic()) {
|
||||
throw new InvalidArgumentException(\sprintf('A synthetic service cannot be decorated: service "%s" cannot decorate "%s".', $id, $inner));
|
||||
}
|
||||
|
||||
if (isset($decoratingDefinitions[$inner])) {
|
||||
$decoratingDefinition = $decoratingDefinitions[$inner];
|
||||
|
||||
$decoratingTags = $decoratingDefinition->getTags();
|
||||
$resetTags = [];
|
||||
|
||||
// Behavior-describing tags must not be transferred out to decorators
|
||||
foreach ($tagsToKeep as $containerTag) {
|
||||
if (isset($decoratingTags[$containerTag])) {
|
||||
$resetTags[$containerTag] = $decoratingTags[$containerTag];
|
||||
unset($decoratingTags[$containerTag]);
|
||||
}
|
||||
}
|
||||
|
||||
$definition->setTags(array_merge($decoratingTags, $definition->getTags()));
|
||||
$decoratingDefinition->setTags($resetTags);
|
||||
$decoratingDefinitions[$inner] = $definition;
|
||||
}
|
||||
|
||||
$container->setAlias($inner, $id)->setPublic($public);
|
||||
}
|
||||
|
||||
foreach ($decoratingDefinitions as $inner => $definition) {
|
||||
$definition->addTag('container.decorator', ['id' => $inner, 'inner' => $decoratedIds[$inner]]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference && '.inner' === (string) $value) {
|
||||
return new Reference($this->currentId, $value->getInvalidBehavior());
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
110
backend/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php
vendored
Normal file
110
backend/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Throws an exception for any Definitions that have errors and still exist.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*/
|
||||
class DefinitionErrorExceptionPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $erroredDefinitions = [];
|
||||
private array $sourceReferences = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
try {
|
||||
parent::process($container);
|
||||
|
||||
$visitedIds = [];
|
||||
|
||||
foreach ($this->erroredDefinitions as $id => $definition) {
|
||||
if ($this->isErrorForRuntime($id, $visitedIds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// only show the first error so the user can focus on it
|
||||
$errors = $definition->getErrors();
|
||||
|
||||
throw new RuntimeException(reset($errors));
|
||||
}
|
||||
} finally {
|
||||
$this->erroredDefinitions = [];
|
||||
$this->sourceReferences = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
parent::processValue($value->getValues());
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof Reference && $this->currentId !== $targetId = (string) $value) {
|
||||
if (
|
||||
ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()
|
||||
|| ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
|
||||
) {
|
||||
$this->sourceReferences[$targetId][$this->currentId ?? ''] ??= true;
|
||||
} else {
|
||||
$this->sourceReferences[$targetId][$this->currentId ?? ''] = false;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition || !$value->hasErrors() || $value->hasTag('container.error')) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$this->erroredDefinitions[$this->currentId ?? ''] = $value;
|
||||
|
||||
return parent::processValue($value);
|
||||
}
|
||||
|
||||
private function isErrorForRuntime(string $id, array &$visitedIds): bool
|
||||
{
|
||||
if (!isset($this->sourceReferences[$id])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($visitedIds[$id])) {
|
||||
return $visitedIds[$id];
|
||||
}
|
||||
|
||||
$visitedIds[$id] = true;
|
||||
|
||||
foreach ($this->sourceReferences[$id] as $sourceId => $isRuntime) {
|
||||
if ($visitedIds[$sourceId] ?? $visitedIds[$sourceId] = $this->isErrorForRuntime($sourceId, $visitedIds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$isRuntime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
34
backend/vendor/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php
vendored
Normal file
34
backend/vendor/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* A pass to automatically process extensions if they implement
|
||||
* CompilerPassInterface.
|
||||
*
|
||||
* @author Wouter J <wouter@wouterj.nl>
|
||||
*/
|
||||
class ExtensionCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if (!$extension instanceof CompilerPassInterface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension->process($container);
|
||||
}
|
||||
}
|
||||
}
|
||||
234
backend/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php
vendored
Normal file
234
backend/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Inline service definitions where this is possible.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InlineServiceDefinitionsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $cloningIds = [];
|
||||
private array $connectedIds = [];
|
||||
private array $notInlinedIds = [];
|
||||
private array $inlinedIds = [];
|
||||
private array $notInlinableIds = [];
|
||||
private array $autowireInline = [];
|
||||
private ?ServiceReferenceGraph $graph = null;
|
||||
|
||||
public function __construct(
|
||||
private ?AnalyzeServiceReferencesPass $analyzingPass = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
if ($this->analyzingPass) {
|
||||
$analyzedContainer = new ContainerBuilder();
|
||||
$analyzedContainer->setAliases($container->getAliases());
|
||||
$analyzedContainer->setDefinitions($container->getDefinitions());
|
||||
foreach ($container->getExpressionLanguageProviders() as $provider) {
|
||||
$analyzedContainer->addExpressionLanguageProvider($provider);
|
||||
}
|
||||
} else {
|
||||
$analyzedContainer = $container;
|
||||
}
|
||||
try {
|
||||
$notInlinableIds = [];
|
||||
$remainingInlinedIds = [];
|
||||
$this->connectedIds = $this->notInlinedIds = $container->getDefinitions();
|
||||
do {
|
||||
if ($this->analyzingPass) {
|
||||
$analyzedContainer->setDefinitions(array_intersect_key($analyzedContainer->getDefinitions(), $this->connectedIds));
|
||||
$this->analyzingPass->process($analyzedContainer);
|
||||
}
|
||||
$this->graph = $analyzedContainer->getCompiler()->getServiceReferenceGraph();
|
||||
$notInlinedIds = $this->notInlinedIds;
|
||||
$notInlinableIds += $this->notInlinableIds;
|
||||
$this->connectedIds = $this->notInlinedIds = $this->inlinedIds = $this->notInlinableIds = [];
|
||||
|
||||
foreach ($analyzedContainer->getDefinitions() as $id => $definition) {
|
||||
if (!$this->graph->hasNode($id)) {
|
||||
continue;
|
||||
}
|
||||
if ($definition->isPublic()) {
|
||||
$this->connectedIds[$id] = true;
|
||||
}
|
||||
foreach ($this->graph->getNode($id)->getOutEdges() as $edge) {
|
||||
if (isset($notInlinedIds[$edge->getSourceNode()->getId()])) {
|
||||
$this->currentId = $id;
|
||||
$this->processValue($definition, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->inlinedIds as $id => $isPublicOrNotShared) {
|
||||
if ($isPublicOrNotShared) {
|
||||
$remainingInlinedIds[$id] = $id;
|
||||
} else {
|
||||
$container->removeDefinition($id);
|
||||
if (!isset($this->autowireInline[$id])) {
|
||||
$analyzedContainer->removeDefinition($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ($this->inlinedIds && $this->analyzingPass);
|
||||
|
||||
foreach ($remainingInlinedIds as $id) {
|
||||
if (isset($notInlinableIds[$id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition($id);
|
||||
|
||||
if (!$definition->isShared() && !$definition->isPublic()) {
|
||||
$container->removeDefinition($id);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$this->container = null;
|
||||
$this->connectedIds = $this->notInlinedIds = $this->inlinedIds = [];
|
||||
$this->notInlinableIds = [];
|
||||
$this->graph = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
// References found in ArgumentInterface::getValues() are not inlineable
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof Definition && $this->cloningIds) {
|
||||
if ($value->isShared()) {
|
||||
return $value;
|
||||
}
|
||||
$value = clone $value;
|
||||
}
|
||||
|
||||
if (!$value instanceof Reference) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
} elseif (!$this->container->hasDefinition($id = (string) $value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$definition = $this->container->getDefinition($id);
|
||||
|
||||
if (isset($this->notInlinableIds[$id]) || !$this->isInlineableDefinition($id, $definition)) {
|
||||
if ($this->currentId !== $id) {
|
||||
$this->notInlinableIds[$id] = true;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
$this->container->log($this, \sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
|
||||
$this->inlinedIds[$id] = $definition->isPublic() || !$definition->isShared();
|
||||
$this->notInlinedIds[$this->currentId ?? ''] = true;
|
||||
|
||||
if ($definition->isShared()) {
|
||||
return $definition;
|
||||
}
|
||||
|
||||
if (isset($this->cloningIds[$id])) {
|
||||
$ids = array_keys($this->cloningIds);
|
||||
$ids[] = $id;
|
||||
|
||||
throw new ServiceCircularReferenceException($id, \array_slice($ids, array_search($id, $ids)));
|
||||
}
|
||||
|
||||
$this->cloningIds[$id] = true;
|
||||
try {
|
||||
return $this->processValue($definition);
|
||||
} finally {
|
||||
unset($this->cloningIds[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the definition is inlineable.
|
||||
*/
|
||||
private function isInlineableDefinition(string $id, Definition $definition): bool
|
||||
{
|
||||
if (str_starts_with($id, '.autowire_inline.')) {
|
||||
$this->autowireInline[$id] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($definition->hasErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic() || $definition->hasTag('container.do_not_inline')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$definition->isShared()) {
|
||||
if (!$this->graph->hasNode($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
|
||||
$srcId = $edge->getSourceNode()->getId();
|
||||
$this->connectedIds[$srcId] = true;
|
||||
if ($edge->isWeak() || $edge->isLazy()) {
|
||||
return !$this->connectedIds[$id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($definition->isPublic()
|
||||
|| $this->currentId === $id
|
||||
|| !$this->graph->hasNode($id)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->connectedIds[$id] = true;
|
||||
|
||||
$srcIds = [];
|
||||
$srcCount = 0;
|
||||
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
|
||||
$srcId = $edge->getSourceNode()->getId();
|
||||
$this->connectedIds[$srcId] = true;
|
||||
if ($edge->isWeak() || $edge->isLazy()) {
|
||||
return false;
|
||||
}
|
||||
$srcIds[$srcId] = true;
|
||||
++$srcCount;
|
||||
}
|
||||
|
||||
if (1 !== \count($srcIds)) {
|
||||
$this->notInlinedIds[$id] = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($srcCount > 1 && \is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$srcDefinition = $this->container->getDefinition($srcId);
|
||||
|
||||
return $srcDefinition->isShared() && !$srcDefinition->isLazy();
|
||||
}
|
||||
}
|
||||
212
backend/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php
vendored
Normal file
212
backend/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Definition\BaseNode;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
/**
|
||||
* Merges extension configs into the container builder.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MergeExtensionConfigurationPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$parameters = $container->getParameterBag()->all();
|
||||
$definitions = $container->getDefinitions();
|
||||
$aliases = $container->getAliases();
|
||||
$exprLangProviders = $container->getExpressionLanguageProviders();
|
||||
$configAvailable = class_exists(BaseNode::class);
|
||||
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if ($extension instanceof PrependExtensionInterface) {
|
||||
$extension->prepend($container);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getExtensions() as $name => $extension) {
|
||||
if (!$config = $container->getExtensionConfig($name)) {
|
||||
// this extension was not called
|
||||
continue;
|
||||
}
|
||||
$resolvingBag = $container->getParameterBag();
|
||||
if ($resolvingBag instanceof EnvPlaceholderParameterBag && $extension instanceof Extension) {
|
||||
// create a dedicated bag so that we can track env vars per-extension
|
||||
$resolvingBag = new MergeExtensionConfigurationParameterBag($resolvingBag);
|
||||
if ($configAvailable) {
|
||||
BaseNode::setPlaceholderUniquePrefix($resolvingBag->getEnvPlaceholderUniquePrefix());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$config = $resolvingBag->resolveValue($config);
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceExtensionName($name);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
try {
|
||||
$tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
|
||||
$tmpContainer->setResourceTracking($container->isTrackingResources());
|
||||
$tmpContainer->addObjectResource($extension);
|
||||
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
|
||||
$tmpContainer->addObjectResource($configuration);
|
||||
}
|
||||
|
||||
foreach ($exprLangProviders as $provider) {
|
||||
$tmpContainer->addExpressionLanguageProvider($provider);
|
||||
}
|
||||
|
||||
$extension->load($config, $tmpContainer);
|
||||
} catch (\Exception $e) {
|
||||
if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
|
||||
$container->getParameterBag()->mergeEnvPlaceholders($resolvingBag);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
|
||||
// don't keep track of env vars that are *overridden* when configs are merged
|
||||
$resolvingBag->freezeAfterProcessing($extension, $tmpContainer);
|
||||
}
|
||||
|
||||
$container->merge($tmpContainer);
|
||||
$container->getParameterBag()->add($parameters);
|
||||
}
|
||||
|
||||
$container->addDefinitions($definitions);
|
||||
$container->addAliases($aliases);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class MergeExtensionConfigurationParameterBag extends EnvPlaceholderParameterBag
|
||||
{
|
||||
private array $processedEnvPlaceholders;
|
||||
|
||||
public function __construct(parent $parameterBag)
|
||||
{
|
||||
parent::__construct($parameterBag->all());
|
||||
$this->mergeEnvPlaceholders($parameterBag);
|
||||
}
|
||||
|
||||
public function freezeAfterProcessing(Extension $extension, ContainerBuilder $container): void
|
||||
{
|
||||
if (!$config = $extension->getProcessedConfigs()) {
|
||||
// Extension::processConfiguration() wasn't called, we cannot know how configs were merged
|
||||
return;
|
||||
}
|
||||
$this->processedEnvPlaceholders = [];
|
||||
|
||||
// serialize config and container to catch env vars nested in object graphs
|
||||
$config = serialize($config).serialize($container->getDefinitions()).serialize($container->getAliases()).serialize($container->getParameterBag()->all());
|
||||
|
||||
if (false === stripos($config, 'env_')) {
|
||||
return;
|
||||
}
|
||||
|
||||
preg_match_all('/env_[a-f0-9]{16}_\w+_[a-f0-9]{32}/Ui', $config, $matches);
|
||||
$usedPlaceholders = array_flip($matches[0]);
|
||||
foreach (parent::getEnvPlaceholders() as $env => $placeholders) {
|
||||
foreach ($placeholders as $placeholder) {
|
||||
if (isset($usedPlaceholders[$placeholder])) {
|
||||
$this->processedEnvPlaceholders[$env] = $placeholders;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getEnvPlaceholders(): array
|
||||
{
|
||||
return $this->processedEnvPlaceholders ?? parent::getEnvPlaceholders();
|
||||
}
|
||||
|
||||
public function getUnusedEnvPlaceholders(): array
|
||||
{
|
||||
return !isset($this->processedEnvPlaceholders) ? [] : array_diff_key(parent::getEnvPlaceholders(), $this->processedEnvPlaceholders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A container builder preventing using methods that wouldn't have any effect from extensions.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
|
||||
{
|
||||
private string $extensionClass;
|
||||
|
||||
public function __construct(ExtensionInterface $extension, ?ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
parent::__construct($parameterBag);
|
||||
|
||||
$this->extensionClass = $extension::class;
|
||||
}
|
||||
|
||||
public function addCompilerPass(CompilerPassInterface $pass, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): static
|
||||
{
|
||||
throw new LogicException(\sprintf('You cannot add compiler pass "%s" from extension "%s". Compiler passes must be registered before the container is compiled.', get_debug_type($pass), $this->extensionClass));
|
||||
}
|
||||
|
||||
public function registerExtension(ExtensionInterface $extension): void
|
||||
{
|
||||
throw new LogicException(\sprintf('You cannot register extension "%s" from "%s". Extensions must be registered before the container is compiled.', get_debug_type($extension), $this->extensionClass));
|
||||
}
|
||||
|
||||
public function compile(bool $resolveEnvPlaceholders = false): void
|
||||
{
|
||||
throw new LogicException(\sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
|
||||
}
|
||||
|
||||
public function resolveEnvPlaceholders(mixed $value, string|bool|null $format = null, ?array &$usedEnvs = null): mixed
|
||||
{
|
||||
if (true !== $format || !\is_string($value)) {
|
||||
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
|
||||
}
|
||||
|
||||
$bag = $this->getParameterBag();
|
||||
$value = $bag->resolveValue($value);
|
||||
|
||||
if (!$bag instanceof EnvPlaceholderParameterBag) {
|
||||
return parent::resolveEnvPlaceholders($value, true, $usedEnvs);
|
||||
}
|
||||
|
||||
foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
|
||||
if (!str_contains($env, ':')) {
|
||||
continue;
|
||||
}
|
||||
foreach ($placeholders as $placeholder) {
|
||||
if (false !== stripos($value, $placeholder)) {
|
||||
throw new RuntimeException(\sprintf('Using a cast in "env(%s)" is incompatible with resolution at compile time in "%s". The logic in the extension should be moved to a compiler pass, or an env parameter with no cast should be used instead.', $env, $this->extensionClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::resolveEnvPlaceholders($value, true, $usedEnvs);
|
||||
}
|
||||
}
|
||||
275
backend/vendor/symfony/dependency-injection/Compiler/PassConfig.php
vendored
Normal file
275
backend/vendor/symfony/dependency-injection/Compiler/PassConfig.php
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Compiler Pass Configuration.
|
||||
*
|
||||
* This class has a default configuration embedded.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class PassConfig
|
||||
{
|
||||
// In the order of execution
|
||||
public const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization';
|
||||
public const TYPE_OPTIMIZE = 'optimization';
|
||||
public const TYPE_BEFORE_REMOVING = 'beforeRemoving';
|
||||
public const TYPE_REMOVE = 'removing';
|
||||
public const TYPE_AFTER_REMOVING = 'afterRemoving';
|
||||
|
||||
private MergeExtensionConfigurationPass $mergePass;
|
||||
private array $afterRemovingPasses;
|
||||
private array $beforeOptimizationPasses;
|
||||
private array $beforeRemovingPasses = [];
|
||||
private array $optimizationPasses;
|
||||
private array $removingPasses;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mergePass = new MergeExtensionConfigurationPass();
|
||||
|
||||
$this->beforeOptimizationPasses = [
|
||||
100 => [
|
||||
new ResolveClassPass(),
|
||||
new RegisterAutoconfigureAttributesPass(),
|
||||
new AutowireAsDecoratorPass(),
|
||||
new AttributeAutoconfigurationPass(),
|
||||
new ResolveInstanceofConditionalsPass(),
|
||||
new RegisterEnvVarProcessorsPass(),
|
||||
],
|
||||
-1000 => [new ExtensionCompilerPass()],
|
||||
];
|
||||
|
||||
$this->optimizationPasses = [[
|
||||
new AutoAliasServicePass(),
|
||||
new ValidateEnvPlaceholdersPass(),
|
||||
new ResolveDecoratorStackPass(),
|
||||
new ResolveAutowireInlineAttributesPass(),
|
||||
new ResolveChildDefinitionsPass(),
|
||||
new RegisterServiceSubscribersPass(),
|
||||
new ResolveParameterPlaceHoldersPass(false, false),
|
||||
new ResolveFactoryClassPass(),
|
||||
new ResolveNamedArgumentsPass(),
|
||||
new AutowireRequiredMethodsPass(),
|
||||
new AutowireRequiredPropertiesPass(),
|
||||
new ResolveBindingsPass(),
|
||||
new ServiceLocatorTagPass(),
|
||||
new DecoratorServicePass(),
|
||||
new CheckDefinitionValidityPass(),
|
||||
new AutowirePass(false),
|
||||
new ServiceLocatorTagPass(),
|
||||
new ResolveTaggedIteratorArgumentPass(),
|
||||
new ResolveServiceSubscribersPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
new AnalyzeServiceReferencesPass(true),
|
||||
new CheckCircularReferencesPass(),
|
||||
new CheckReferenceValidityPass(),
|
||||
new CheckArgumentsValidityPass(false),
|
||||
]];
|
||||
|
||||
$this->removingPasses = [[
|
||||
new RemovePrivateAliasesPass(),
|
||||
new ReplaceAliasByActualDefinitionPass(),
|
||||
new RemoveAbstractDefinitionsPass(),
|
||||
new RemoveUnusedDefinitionsPass(),
|
||||
new AnalyzeServiceReferencesPass(),
|
||||
new CheckExceptionOnInvalidReferenceBehaviorPass(),
|
||||
new InlineServiceDefinitionsPass(new AnalyzeServiceReferencesPass()),
|
||||
new AnalyzeServiceReferencesPass(),
|
||||
new DefinitionErrorExceptionPass(),
|
||||
]];
|
||||
|
||||
$this->afterRemovingPasses = [
|
||||
0 => [
|
||||
new ResolveHotPathPass(),
|
||||
new ResolveNoPreloadPass(),
|
||||
new AliasDeprecatedPublicServicesPass(),
|
||||
],
|
||||
// Let build parameters be available as late as possible
|
||||
// Don't remove array parameters since ResolveParameterPlaceHoldersPass doesn't resolve them
|
||||
-2048 => [new RemoveBuildParametersPass(true)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all passes in order to be processed.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getPasses(): array
|
||||
{
|
||||
return array_merge(
|
||||
[$this->mergePass],
|
||||
$this->getBeforeOptimizationPasses(),
|
||||
$this->getOptimizationPasses(),
|
||||
$this->getBeforeRemovingPasses(),
|
||||
$this->getRemovingPasses(),
|
||||
$this->getAfterRemovingPasses()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pass.
|
||||
*
|
||||
* @throws InvalidArgumentException when a pass type doesn't exist
|
||||
*/
|
||||
public function addPass(CompilerPassInterface $pass, string $type = self::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): void
|
||||
{
|
||||
$property = $type.'Passes';
|
||||
if (!isset($this->$property)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid type "%s".', $type));
|
||||
}
|
||||
|
||||
$passes = &$this->$property;
|
||||
|
||||
if (!isset($passes[$priority])) {
|
||||
$passes[$priority] = [];
|
||||
}
|
||||
$passes[$priority][] = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the AfterRemoving pass.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getAfterRemovingPasses(): array
|
||||
{
|
||||
return $this->sortPasses($this->afterRemovingPasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the BeforeOptimization pass.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getBeforeOptimizationPasses(): array
|
||||
{
|
||||
return $this->sortPasses($this->beforeOptimizationPasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the BeforeRemoving pass.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getBeforeRemovingPasses(): array
|
||||
{
|
||||
return $this->sortPasses($this->beforeRemovingPasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the Optimization pass.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getOptimizationPasses(): array
|
||||
{
|
||||
return $this->sortPasses($this->optimizationPasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the Removing pass.
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
public function getRemovingPasses(): array
|
||||
{
|
||||
return $this->sortPasses($this->removingPasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Merge pass.
|
||||
*/
|
||||
public function getMergePass(): CompilerPassInterface
|
||||
{
|
||||
return $this->mergePass;
|
||||
}
|
||||
|
||||
public function setMergePass(CompilerPassInterface $pass): void
|
||||
{
|
||||
$this->mergePass = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AfterRemoving passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*/
|
||||
public function setAfterRemovingPasses(array $passes): void
|
||||
{
|
||||
$this->afterRemovingPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeOptimization passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*/
|
||||
public function setBeforeOptimizationPasses(array $passes): void
|
||||
{
|
||||
$this->beforeOptimizationPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeRemoving passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*/
|
||||
public function setBeforeRemovingPasses(array $passes): void
|
||||
{
|
||||
$this->beforeRemovingPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Optimization passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*/
|
||||
public function setOptimizationPasses(array $passes): void
|
||||
{
|
||||
$this->optimizationPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Removing passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*/
|
||||
public function setRemovingPasses(array $passes): void
|
||||
{
|
||||
$this->removingPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort passes by priority.
|
||||
*
|
||||
* @param array $passes CompilerPassInterface instances with their priority as key
|
||||
*
|
||||
* @return CompilerPassInterface[]
|
||||
*/
|
||||
private function sortPasses(array $passes): array
|
||||
{
|
||||
if (0 === \count($passes)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
krsort($passes);
|
||||
|
||||
// Flatten the array
|
||||
return array_merge(...$passes);
|
||||
}
|
||||
}
|
||||
210
backend/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php
vendored
Normal file
210
backend/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
/**
|
||||
* Trait that allows a generic method to find and sort service by priority option in the tag.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
trait PriorityTaggedServiceTrait
|
||||
{
|
||||
/**
|
||||
* Finds all services with the given tag name and order them by their priority.
|
||||
*
|
||||
* The order of additions must be respected for services having the same priority,
|
||||
* and knowing that the \SplPriorityQueue class does not respect the FIFO method,
|
||||
* we should not use that class.
|
||||
*
|
||||
* @see https://bugs.php.net/53710
|
||||
* @see https://bugs.php.net/60926
|
||||
*
|
||||
* @return Reference[]
|
||||
*/
|
||||
private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagName, ContainerBuilder $container, array $exclude = []): array
|
||||
{
|
||||
$indexAttribute = $defaultIndexMethod = $needsIndexes = $defaultPriorityMethod = null;
|
||||
|
||||
if ($tagName instanceof TaggedIteratorArgument) {
|
||||
$indexAttribute = $tagName->getIndexAttribute();
|
||||
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
|
||||
$needsIndexes = $tagName->needsIndexes();
|
||||
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod() ?? 'getDefaultPriority';
|
||||
$exclude = array_merge($exclude, $tagName->getExclude());
|
||||
$tagName = $tagName->getTag();
|
||||
}
|
||||
|
||||
$parameterBag = $container->getParameterBag();
|
||||
$services = [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
||||
if (\in_array($serviceId, $exclude, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaultPriority = $defaultAttributePriority = null;
|
||||
$defaultIndex = $defaultAttributeIndex = null;
|
||||
$definition = $container->getDefinition($serviceId);
|
||||
$class = $definition->getClass();
|
||||
$class = $container->getParameterBag()->resolveValue($class) ?: null;
|
||||
$reflector = null !== $class ? $container->getReflectionClass($class) : null;
|
||||
$phpAttributes = $definition->isAutoconfigured() && !$definition->hasTag('container.ignore_attributes') ? $reflector?->getAttributes(AsTaggedItem::class) : [];
|
||||
|
||||
foreach ($phpAttributes ??= [] as $i => $attribute) {
|
||||
$attribute = $attribute->newInstance();
|
||||
$phpAttributes[$i] = [
|
||||
'priority' => $attribute->priority,
|
||||
$indexAttribute ?? '' => $attribute->index,
|
||||
];
|
||||
if (null === $defaultAttributePriority) {
|
||||
$defaultAttributePriority = $attribute->priority ?? 0;
|
||||
$defaultAttributeIndex = $attribute->index;
|
||||
}
|
||||
}
|
||||
if (1 >= \count($phpAttributes)) {
|
||||
$phpAttributes = [];
|
||||
}
|
||||
|
||||
// For decorated services, walk the decoration chain to find #[AsTaggedItem] on the original service
|
||||
$innerClass = null;
|
||||
$innerDef = $definition;
|
||||
while ($innerId = $innerDef->getTag('container.decorator')[0]['inner'] ?? null) {
|
||||
if (!$container->has($innerId)) {
|
||||
break;
|
||||
}
|
||||
$innerDef = $container->findDefinition($innerId);
|
||||
$innerClass = $container->getParameterBag()->resolveValue($innerDef->getClass()) ?: null;
|
||||
}
|
||||
$innerReflector = null !== $innerClass ? $container->getReflectionClass($innerClass) : null;
|
||||
|
||||
$attributes = array_values($attributes);
|
||||
for ($i = 0; $i < \count($attributes); ++$i) {
|
||||
if (!($attribute = $attributes[$i]) && $phpAttributes) {
|
||||
array_splice($attributes, $i--, 1, $phpAttributes);
|
||||
continue;
|
||||
}
|
||||
|
||||
$index = $priority = null;
|
||||
|
||||
if (isset($attribute['priority'])) {
|
||||
$priority = $attribute['priority'];
|
||||
} elseif (null === $defaultPriority && $defaultPriorityMethod && $reflector) {
|
||||
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultAttributePriority;
|
||||
if (null === $defaultPriority && null !== $innerReflector) {
|
||||
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $innerReflector, $defaultPriorityMethod, $tagName, 'priority');
|
||||
}
|
||||
}
|
||||
$priority ??= $defaultPriority ??= 0;
|
||||
|
||||
if (null === $indexAttribute && !$defaultIndexMethod && !$needsIndexes) {
|
||||
$services[] = [$priority, $i, null, $serviceId, null];
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if (null !== $indexAttribute && isset($attribute[$indexAttribute])) {
|
||||
$index = $parameterBag->resolveValue($attribute[$indexAttribute]);
|
||||
}
|
||||
if (null === $index && null === $defaultIndex && $defaultPriorityMethod && $reflector) {
|
||||
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute) ?? $defaultAttributeIndex;
|
||||
if (null === $defaultIndex && null !== $innerReflector) {
|
||||
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $innerReflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute);
|
||||
if (null === $defaultIndex) {
|
||||
foreach ($innerReflector->getAttributes(AsTaggedItem::class) as $innerAttr) {
|
||||
$defaultIndex = $innerAttr->newInstance()->index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$index ??= $defaultIndex ??= $definition->getTag('container.decorator')[0]['id'] ?? $serviceId;
|
||||
|
||||
$services[] = [$priority, $i, $index, $serviceId, $class];
|
||||
}
|
||||
}
|
||||
|
||||
uasort($services, static fn ($a, $b) => $b[0] <=> $a[0] ?: $a[1] <=> $b[1]);
|
||||
|
||||
$refs = [];
|
||||
foreach ($services as [, , $index, $serviceId, $class]) {
|
||||
$reference = match (true) {
|
||||
!$class => new Reference($serviceId),
|
||||
$index === $serviceId => new TypedReference($serviceId, $class),
|
||||
default => new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $index),
|
||||
};
|
||||
|
||||
if (null === $index) {
|
||||
$refs[] = $reference;
|
||||
} else {
|
||||
$refs[$index] = $reference;
|
||||
}
|
||||
}
|
||||
|
||||
return $refs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class PriorityTaggedServiceUtil
|
||||
{
|
||||
public static function getDefault(string $serviceId, \ReflectionClass $r, string $defaultMethod, string $tagName, ?string $indexAttribute): string|int|null
|
||||
{
|
||||
if ($r->isInterface() || !$r->hasMethod($defaultMethod)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$class = $r->name;
|
||||
|
||||
if (null !== $indexAttribute) {
|
||||
$service = $class !== $serviceId ? \sprintf('service "%s"', $serviceId) : 'on the corresponding service';
|
||||
$message = [\sprintf('Either method "%s::%s()" should ', $class, $defaultMethod), \sprintf(' or tag "%s" on %s is missing attribute "%s".', $tagName, $service, $indexAttribute)];
|
||||
} else {
|
||||
$message = [\sprintf('Method "%s::%s()" should ', $class, $defaultMethod), '.'];
|
||||
}
|
||||
|
||||
if (!($rm = $r->getMethod($defaultMethod))->isStatic()) {
|
||||
throw new InvalidArgumentException(implode('be static', $message));
|
||||
}
|
||||
|
||||
if (!$rm->isPublic()) {
|
||||
throw new InvalidArgumentException(implode('be public', $message));
|
||||
}
|
||||
|
||||
$default = $rm->invoke(null);
|
||||
|
||||
if ('priority' === $indexAttribute) {
|
||||
if (!\is_int($default)) {
|
||||
throw new InvalidArgumentException(implode(\sprintf('return int (got "%s")', get_debug_type($default)), $message));
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (\is_int($default)) {
|
||||
$default = (string) $default;
|
||||
}
|
||||
|
||||
if (!\is_string($default)) {
|
||||
throw new InvalidArgumentException(implode(\sprintf('return string|int (got "%s")', get_debug_type($default)), $message));
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
103
backend/vendor/symfony/dependency-injection/Compiler/RegisterAutoconfigureAttributesPass.php
vendored
Normal file
103
backend/vendor/symfony/dependency-injection/Compiler/RegisterAutoconfigureAttributesPass.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Lazy;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\AutoconfigureFailedException;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
|
||||
/**
|
||||
* Reads #[Autoconfigure] attributes on definitions that are autoconfigured
|
||||
* and don't have the "container.ignore_attributes" tag.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class RegisterAutoconfigureAttributesPass implements CompilerPassInterface
|
||||
{
|
||||
private static \Closure $registerForAutoconfiguration;
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($this->accept($definition) && $class = $container->getReflectionClass($definition->getClass(), false)) {
|
||||
$this->processClass($container, $class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function accept(Definition $definition): bool
|
||||
{
|
||||
return $definition->isAutoconfigured() && !$definition->hasTag('container.ignore_attributes');
|
||||
}
|
||||
|
||||
public function processClass(ContainerBuilder $container, \ReflectionClass $class): void
|
||||
{
|
||||
$autoconfigure = $class->getAttributes(Autoconfigure::class, \ReflectionAttribute::IS_INSTANCEOF);
|
||||
$lazy = $class->getAttributes(Lazy::class, \ReflectionAttribute::IS_INSTANCEOF);
|
||||
|
||||
if ($autoconfigure && $lazy) {
|
||||
throw new AutoconfigureFailedException($class->name, 'Using both attributes #[Lazy] and #[Autoconfigure] on an argument is not allowed; use the "lazy" parameter of #[Autoconfigure] instead.');
|
||||
}
|
||||
|
||||
$attributes = array_merge($autoconfigure, $lazy);
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
self::registerForAutoconfiguration($container, $class, $attribute);
|
||||
}
|
||||
}
|
||||
|
||||
private static function registerForAutoconfiguration(ContainerBuilder $container, \ReflectionClass $class, \ReflectionAttribute $attribute): void
|
||||
{
|
||||
if (isset(self::$registerForAutoconfiguration)) {
|
||||
(self::$registerForAutoconfiguration)($container, $class, $attribute);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$parseDefinitions = new \ReflectionMethod(YamlFileLoader::class, 'parseDefinitions');
|
||||
$yamlLoader = $parseDefinitions->getDeclaringClass()->newInstanceWithoutConstructor();
|
||||
|
||||
self::$registerForAutoconfiguration = static function (ContainerBuilder $container, \ReflectionClass $class, \ReflectionAttribute $attribute) use ($parseDefinitions, $yamlLoader) {
|
||||
$attribute = (array) $attribute->newInstance();
|
||||
|
||||
foreach (['tags', 'resourceTags'] as $type) {
|
||||
foreach ($attribute[$type] ?? [] as $i => $tag) {
|
||||
if (\is_array($tag) && [0] === array_keys($tag)) {
|
||||
$attribute[$type][$i] = [$class->name => $tag[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($attribute['resourceTags'])) {
|
||||
$attribute['resource_tags'] = $attribute['resourceTags'];
|
||||
}
|
||||
unset($attribute['resourceTags']);
|
||||
|
||||
$parseDefinitions->invoke(
|
||||
$yamlLoader,
|
||||
[
|
||||
'services' => [
|
||||
'_instanceof' => [
|
||||
$class->name => [$container->registerForAutoconfiguration($class->name)] + $attribute,
|
||||
],
|
||||
],
|
||||
],
|
||||
$class->getFileName(),
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
(self::$registerForAutoconfiguration)($container, $class, $attribute);
|
||||
}
|
||||
}
|
||||
75
backend/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php
vendored
Normal file
75
backend/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\EnvVarProcessor;
|
||||
use Symfony\Component\DependencyInjection\EnvVarProcessorInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Creates the container.env_var_processors_locator service.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RegisterEnvVarProcessorsPass implements CompilerPassInterface
|
||||
{
|
||||
private const ALLOWED_TYPES = ['array', 'bool', 'float', 'int', 'string', \BackedEnum::class];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$bag = $container->getParameterBag();
|
||||
$types = [];
|
||||
$processors = [];
|
||||
foreach ($container->findTaggedServiceIds('container.env_var_processor') as $id => $tags) {
|
||||
if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) {
|
||||
throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
} elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) {
|
||||
throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class));
|
||||
}
|
||||
foreach ($class::getProvidedTypes() as $prefix => $type) {
|
||||
$processors[$prefix] = new Reference($id);
|
||||
$types[$prefix] = self::validateProvidedTypes($type, $class);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bag instanceof EnvPlaceholderParameterBag) {
|
||||
foreach (EnvVarProcessor::getProvidedTypes() as $prefix => $type) {
|
||||
if (!isset($types[$prefix])) {
|
||||
$types[$prefix] = self::validateProvidedTypes($type, EnvVarProcessor::class);
|
||||
}
|
||||
}
|
||||
$bag->setProvidedTypes($types);
|
||||
}
|
||||
|
||||
if ($processors) {
|
||||
$container->setAlias('container.env_var_processors_locator', (string) ServiceLocatorTagPass::register($container, $processors))
|
||||
->setPublic(true)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateProvidedTypes(string $types, string $class): array
|
||||
{
|
||||
$types = explode('|', $types);
|
||||
|
||||
foreach ($types as $type) {
|
||||
if (!\in_array($type, self::ALLOWED_TYPES, true)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid type "%s" returned by "%s::getProvidedTypes()", expected one of "%s".', $type, $class, implode('", "', self::ALLOWED_TYPES)));
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
}
|
||||
60
backend/vendor/symfony/dependency-injection/Compiler/RegisterReverseContainerPass.php
vendored
Normal file
60
backend/vendor/symfony/dependency-injection/Compiler/RegisterReverseContainerPass.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RegisterReverseContainerPass implements CompilerPassInterface
|
||||
{
|
||||
public function __construct(
|
||||
private bool $beforeRemoving,
|
||||
) {
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('reverse_container')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$refType = $this->beforeRemoving ? ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
$services = [];
|
||||
foreach ($container->findTaggedServiceIds('container.reversible') as $id => $tags) {
|
||||
$services[$id] = new Reference($id, $refType);
|
||||
}
|
||||
|
||||
if ($this->beforeRemoving) {
|
||||
// prevent inlining of the reverse container
|
||||
$services['reverse_container'] = new Reference('reverse_container', $refType);
|
||||
}
|
||||
$locator = $container->getDefinition('reverse_container')->getArgument(1);
|
||||
|
||||
if ($locator instanceof Reference) {
|
||||
$locator = $container->getDefinition((string) $locator);
|
||||
}
|
||||
if ($locator instanceof Definition) {
|
||||
foreach ($services as $id => $ref) {
|
||||
$services[$id] = new ServiceClosureArgument($ref);
|
||||
}
|
||||
$locator->replaceArgument(0, $services);
|
||||
} else {
|
||||
$locator->setValues($services);
|
||||
}
|
||||
}
|
||||
}
|
||||
143
backend/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php
vendored
Normal file
143
backend/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Contracts\Service\Attribute\SubscribedService;
|
||||
use Symfony\Contracts\Service\ServiceCollectionInterface;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Compiler pass to register tagged services that require a service locator.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Definition || $value->isAbstract() || $value->isSynthetic() || !$value->hasTag('container.service_subscriber')) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$serviceMap = [];
|
||||
$autowire = $value->isAutowired();
|
||||
|
||||
foreach ($value->getTag('container.service_subscriber') as $attributes) {
|
||||
if (!$attributes) {
|
||||
$autowire = true;
|
||||
continue;
|
||||
}
|
||||
ksort($attributes);
|
||||
if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) {
|
||||
throw new InvalidArgumentException(\sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $this->currentId));
|
||||
}
|
||||
if (!\array_key_exists('id', $attributes)) {
|
||||
throw new InvalidArgumentException(\sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $this->currentId));
|
||||
}
|
||||
if (!\array_key_exists('key', $attributes)) {
|
||||
$attributes['key'] = $attributes['id'];
|
||||
}
|
||||
if (isset($serviceMap[$attributes['key']])) {
|
||||
continue;
|
||||
}
|
||||
$serviceMap[$attributes['key']] = new Reference($attributes['id']);
|
||||
}
|
||||
$class = $value->getClass();
|
||||
|
||||
if (!$r = $this->container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $this->currentId));
|
||||
}
|
||||
if (!$r->isSubclassOf(ServiceSubscriberInterface::class)) {
|
||||
throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $this->currentId, ServiceSubscriberInterface::class));
|
||||
}
|
||||
$class = $r->name;
|
||||
$subscriberMap = [];
|
||||
|
||||
foreach ($class::getSubscribedServices() as $key => $type) {
|
||||
$attributes = [];
|
||||
|
||||
if (!isset($serviceMap[$key]) && $type instanceof Autowire) {
|
||||
$subscriberMap[$key] = $type;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type instanceof SubscribedService) {
|
||||
$key = $type->key ?? $key;
|
||||
$attributes = $type->attributes;
|
||||
$type = ($type->nullable ? '?' : '').($type->type ?? throw new InvalidArgumentException(\sprintf('When "%s::getSubscribedServices()" returns "%s", a type must be set.', $class, SubscribedService::class)));
|
||||
}
|
||||
|
||||
if (!\is_string($type) || !preg_match('/(?(DEFINE)(?<cn>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?(DEFINE)(?<fqcn>(?&cn)(?:\\\\(?&cn))*+))^\??(?&fqcn)(?:(?:\|(?&fqcn))*+|(?:&(?&fqcn))*+)$/', $type)) {
|
||||
throw new InvalidArgumentException(\sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $this->currentId, $key, \is_string($type) ? $type : get_debug_type($type)));
|
||||
}
|
||||
$optionalBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
if ('?' === $type[0]) {
|
||||
$type = substr($type, 1);
|
||||
$optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
|
||||
}
|
||||
if (\is_int($name = $key)) {
|
||||
$key = $type;
|
||||
$name = null;
|
||||
}
|
||||
if (!isset($serviceMap[$key])) {
|
||||
if (!$autowire) {
|
||||
throw new InvalidArgumentException(\sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $this->currentId, $key, $class));
|
||||
}
|
||||
$serviceMap[$key] = new Reference($type);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
if (false !== $i = strpos($name, '::get')) {
|
||||
$name = lcfirst(substr($name, 5 + $i));
|
||||
} elseif (str_contains($name, '::')) {
|
||||
$name = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $name && !$this->container->has($name) && !$this->container->has($type.' $'.$name)) {
|
||||
$camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name))));
|
||||
$name = $this->container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name;
|
||||
}
|
||||
|
||||
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior, $name, $attributes);
|
||||
unset($serviceMap[$key]);
|
||||
}
|
||||
|
||||
if ($serviceMap = array_keys($serviceMap)) {
|
||||
$message = \sprintf(1 < \count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap)));
|
||||
throw new InvalidArgumentException(\sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId));
|
||||
}
|
||||
|
||||
$locatorRef = ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId);
|
||||
|
||||
$value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]);
|
||||
|
||||
$value->setBindings([
|
||||
PsrContainerInterface::class => new BoundArgument($locatorRef, false),
|
||||
ServiceProviderInterface::class => new BoundArgument($locatorRef, false),
|
||||
ServiceCollectionInterface::class => new BoundArgument($locatorRef, false),
|
||||
] + $value->getBindings());
|
||||
|
||||
return parent::processValue($value);
|
||||
}
|
||||
}
|
||||
34
backend/vendor/symfony/dependency-injection/Compiler/RemoveAbstractDefinitionsPass.php
vendored
Normal file
34
backend/vendor/symfony/dependency-injection/Compiler/RemoveAbstractDefinitionsPass.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Removes abstract Definitions.
|
||||
*/
|
||||
class RemoveAbstractDefinitionsPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Removes abstract definitions from the ContainerBuilder.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isAbstract()) {
|
||||
$container->resolveEnvPlaceholders($definition);
|
||||
$container->removeDefinition($id);
|
||||
$container->log($this, \sprintf('Removed service "%s"; reason: abstract.', $id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
backend/vendor/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php
vendored
Normal file
50
backend/vendor/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class RemoveBuildParametersPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $removedParameters = [];
|
||||
|
||||
public function __construct(
|
||||
private bool $preserveArrays = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$parameterBag = $container->getParameterBag();
|
||||
$this->removedParameters = [];
|
||||
|
||||
foreach ($parameterBag->all() as $name => $value) {
|
||||
if ('.' === ($name[0] ?? '') && (!$this->preserveArrays || !\is_array($value))) {
|
||||
$this->removedParameters[$name] = $value;
|
||||
|
||||
$parameterBag->remove($name);
|
||||
$container->log($this, \sprintf('Removing build parameter "%s".', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getRemovedParameters(): array
|
||||
{
|
||||
return $this->removedParameters;
|
||||
}
|
||||
}
|
||||
39
backend/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php
vendored
Normal file
39
backend/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Remove private aliases from the container. They were only used to establish
|
||||
* dependencies between services, and these dependencies have been resolved in
|
||||
* one of the previous passes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RemovePrivateAliasesPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Removes private aliases from the ContainerBuilder.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($alias->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container->removeAlias($id);
|
||||
$container->log($this, \sprintf('Removed service "%s"; reason: private alias.', $id));
|
||||
}
|
||||
}
|
||||
}
|
||||
89
backend/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php
vendored
Normal file
89
backend/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Removes unused service definitions from the container.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RemoveUnusedDefinitionsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $connectedIds = [];
|
||||
|
||||
/**
|
||||
* Processes the ContainerBuilder to remove unused definitions.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
try {
|
||||
$this->enableExpressionProcessing();
|
||||
$this->container = $container;
|
||||
$connectedIds = [];
|
||||
$aliases = $container->getAliases();
|
||||
|
||||
foreach ($aliases as $id => $alias) {
|
||||
if ($alias->isPublic()) {
|
||||
$this->connectedIds[] = (string) $aliases[$id];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isPublic()) {
|
||||
$connectedIds[$id] = true;
|
||||
$this->processValue($definition);
|
||||
}
|
||||
}
|
||||
|
||||
while ($this->connectedIds) {
|
||||
$ids = $this->connectedIds;
|
||||
$this->connectedIds = [];
|
||||
foreach ($ids as $id) {
|
||||
if (!isset($connectedIds[$id]) && $container->hasDefinition($id)) {
|
||||
$connectedIds[$id] = true;
|
||||
$this->processValue($container->getDefinition($id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if (!isset($connectedIds[$id])) {
|
||||
$container->removeDefinition($id);
|
||||
$container->resolveEnvPlaceholders(!$definition->hasErrors() ? serialize($definition) : $definition);
|
||||
$container->log($this, \sprintf('Removed service "%s"; reason: unused.', $id));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$this->container = null;
|
||||
$this->connectedIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Reference) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) {
|
||||
$this->connectedIds[] = (string) $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
109
backend/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php
vendored
Normal file
109
backend/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Replaces aliases with actual service definitions, effectively removing these
|
||||
* aliases.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ReplaceAliasByActualDefinitionPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $replacements;
|
||||
|
||||
/**
|
||||
* Process the Container to replace aliases with service definitions.
|
||||
*
|
||||
* @throws InvalidArgumentException if the service definition does not exist
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
// First collect all alias targets that need to be replaced
|
||||
$seenAliasTargets = [];
|
||||
$replacements = [];
|
||||
|
||||
// Sort aliases so non-deprecated ones come first. This ensures that when
|
||||
// multiple aliases point to the same private definition, non-deprecated
|
||||
// aliases get priority for renaming. Otherwise, the definition might be
|
||||
// renamed to a deprecated alias ID, causing the original service ID to
|
||||
// become an alias to the deprecated one (inverting the alias chain).
|
||||
$aliases = $container->getAliases();
|
||||
uasort($aliases, static fn ($a, $b) => $a->isDeprecated() <=> $b->isDeprecated());
|
||||
|
||||
foreach ($aliases as $definitionId => $target) {
|
||||
$targetId = (string) $target;
|
||||
// Special case: leave this target alone
|
||||
if ('service_container' === $targetId) {
|
||||
continue;
|
||||
}
|
||||
// Check if target needs to be replaced
|
||||
if (isset($replacements[$targetId])) {
|
||||
$container->setAlias($definitionId, $replacements[$targetId])->setPublic($target->isPublic());
|
||||
|
||||
if ($target->isDeprecated()) {
|
||||
$container->getAlias($definitionId)->setDeprecated(...array_values($target->getDeprecation('%alias_id%')));
|
||||
}
|
||||
}
|
||||
// No need to process the same target twice
|
||||
if (isset($seenAliasTargets[$targetId])) {
|
||||
continue;
|
||||
}
|
||||
// Process new target
|
||||
$seenAliasTargets[$targetId] = true;
|
||||
try {
|
||||
$definition = $container->getDefinition($targetId);
|
||||
} catch (ServiceNotFoundException $e) {
|
||||
if ('' !== $e->getId() && '@' === $e->getId()[0]) {
|
||||
throw new ServiceNotFoundException($e->getId(), $e->getSourceId(), null, [substr($e->getId(), 1)]);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
if ($definition->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
// Remove private definition and schedule for replacement
|
||||
$definition->setPublic($target->isPublic());
|
||||
$container->setDefinition($definitionId, $definition);
|
||||
$container->removeDefinition($targetId);
|
||||
$replacements[$targetId] = $definitionId;
|
||||
|
||||
if ($target->isPublic() && $target->isDeprecated()) {
|
||||
$definition->addTag('container.private', $target->getDeprecation('%service_id%'));
|
||||
}
|
||||
}
|
||||
$this->replacements = $replacements;
|
||||
|
||||
parent::process($container);
|
||||
$this->replacements = [];
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference && isset($this->replacements[$referenceId = (string) $value])) {
|
||||
// Perform the replacement
|
||||
$newId = $this->replacements[$referenceId];
|
||||
$value = new Reference($newId, $value->getInvalidBehavior());
|
||||
$this->container->log($this, \sprintf('Changed reference of service "%s" previously pointing to "%s" to "%s".', $this->currentId, $referenceId, $newId));
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
134
backend/vendor/symfony/dependency-injection/Compiler/ResolveAutowireInlineAttributesPass.php
vendored
Normal file
134
backend/vendor/symfony/dependency-injection/Compiler/ResolveAutowireInlineAttributesPass.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireInline;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* Inspects existing autowired services for {@see AutowireInline} attributes and registers the definitions for reuse.
|
||||
*
|
||||
* @author Ismail Özgün Turan <oezguen.turan@dadadev.com>
|
||||
*/
|
||||
class ResolveAutowireInlineAttributesPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private int $counter;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if (!$value instanceof Definition || !$value->isAutowired() || !$value->getClass() || $value->hasTag('container.ignore_attributes')) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($isRoot) {
|
||||
$this->counter = 0;
|
||||
}
|
||||
|
||||
$isChildDefinition = $value instanceof ChildDefinition;
|
||||
|
||||
try {
|
||||
$constructor = $this->getConstructor($value, false);
|
||||
} catch (RuntimeException) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($constructor) {
|
||||
$arguments = $this->registerAutowireInlineAttributes($constructor, $value->getArguments(), $isChildDefinition);
|
||||
|
||||
if ($arguments !== $value->getArguments()) {
|
||||
$value->setArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
$methodCalls = $value->getMethodCalls();
|
||||
|
||||
foreach ($methodCalls as $i => $call) {
|
||||
[$method, $arguments] = $call;
|
||||
|
||||
try {
|
||||
$method = $this->getReflectionMethod($value, $method);
|
||||
} catch (RuntimeException) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments = $this->registerAutowireInlineAttributes($method, $arguments, $isChildDefinition);
|
||||
|
||||
if ($arguments !== $call[1]) {
|
||||
$methodCalls[$i][1] = $arguments;
|
||||
}
|
||||
}
|
||||
|
||||
if ($methodCalls !== $value->getMethodCalls()) {
|
||||
$value->setMethodCalls($methodCalls);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function registerAutowireInlineAttributes(\ReflectionFunctionAbstract $method, array $arguments, bool $isChildDefinition): array
|
||||
{
|
||||
$parameters = $method->getParameters();
|
||||
|
||||
if ($method->isVariadic()) {
|
||||
array_pop($parameters);
|
||||
}
|
||||
$paramResolverContainer = new ContainerBuilder($this->container->getParameterBag());
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
if ($isChildDefinition) {
|
||||
$index = 'index_'.$index;
|
||||
}
|
||||
|
||||
if (\array_key_exists('$'.$parameter->name, $arguments) || (\array_key_exists($index, $arguments) && '' !== $arguments[$index])) {
|
||||
$attribute = \array_key_exists('$'.$parameter->name, $arguments) ? $arguments['$'.$parameter->name] : $arguments[$index];
|
||||
if (!$attribute instanceof AutowireInline) {
|
||||
continue;
|
||||
}
|
||||
} elseif (!$attribute = $parameter->getAttributes(AutowireInline::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
|
||||
continue;
|
||||
} else {
|
||||
$attribute = $attribute->newInstance();
|
||||
}
|
||||
|
||||
$type = ProxyHelper::exportType($parameter, true);
|
||||
|
||||
if (!$type && isset($arguments[$index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition = $attribute->buildDefinition($attribute->value, $type, $parameter);
|
||||
|
||||
$paramResolverContainer->setDefinition('.autowire_inline', $definition);
|
||||
(new ResolveParameterPlaceHoldersPass(false, false))->process($paramResolverContainer);
|
||||
|
||||
$id = '.autowire_inline.'.$this->currentId.'.'.++$this->counter;
|
||||
|
||||
$this->container->setDefinition($id, $definition);
|
||||
$arguments[$isChildDefinition ? '$'.$parameter->name : $index] = new Reference($id);
|
||||
|
||||
if ($definition->isAutowired()) {
|
||||
$this->processValue($definition);
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
272
backend/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php
vendored
Normal file
272
backend/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* @author Guilhem Niot <guilhem.niot@gmail.com>
|
||||
*/
|
||||
class ResolveBindingsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $usedBindings = [];
|
||||
private array $unusedBindings = [];
|
||||
private array $errorMessages = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->usedBindings = $container->getRemovedBindingIds();
|
||||
|
||||
try {
|
||||
parent::process($container);
|
||||
|
||||
foreach ($this->unusedBindings as [$key, $serviceId, $bindingType, $file]) {
|
||||
$argumentType = $argumentName = $message = null;
|
||||
|
||||
if (str_contains($key, ' ')) {
|
||||
[$argumentType, $argumentName] = explode(' ', $key, 2);
|
||||
} elseif ('$' === $key[0]) {
|
||||
$argumentName = $key;
|
||||
} else {
|
||||
$argumentType = $key;
|
||||
}
|
||||
|
||||
if ($argumentType) {
|
||||
$message .= \sprintf('of type "%s" ', $argumentType);
|
||||
}
|
||||
|
||||
if ($argumentName) {
|
||||
$message .= \sprintf('named "%s" ', $argumentName);
|
||||
}
|
||||
|
||||
if (BoundArgument::DEFAULTS_BINDING === $bindingType) {
|
||||
$message .= 'under "_defaults"';
|
||||
} elseif (BoundArgument::INSTANCEOF_BINDING === $bindingType) {
|
||||
$message .= 'under "_instanceof"';
|
||||
} else {
|
||||
$message .= \sprintf('for service "%s"', $serviceId);
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
$message .= \sprintf(' in file "%s"', $file);
|
||||
}
|
||||
|
||||
$message = \sprintf('A binding is configured for an argument %s, but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo.', $message);
|
||||
|
||||
if ($this->errorMessages) {
|
||||
$message .= \sprintf("\nCould be related to%s:", 1 < \count($this->errorMessages) ? ' one of' : '');
|
||||
}
|
||||
foreach ($this->errorMessages as $m) {
|
||||
$message .= "\n - ".$m;
|
||||
}
|
||||
throw new InvalidArgumentException($message);
|
||||
}
|
||||
} finally {
|
||||
$this->usedBindings = [];
|
||||
$this->unusedBindings = [];
|
||||
$this->errorMessages = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof TypedReference && $value->getType() === (string) $value) {
|
||||
// Already checked
|
||||
$bindings = $this->container->getDefinition($this->currentId)->getBindings();
|
||||
$name = $value->getName();
|
||||
|
||||
if (isset($name, $bindings[$name = $value.' $'.$name])) {
|
||||
return $this->getBindingValue($bindings[$name]);
|
||||
}
|
||||
|
||||
if (isset($bindings[$value->getType()])) {
|
||||
return $this->getBindingValue($bindings[$value->getType()]);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition || !$bindings = $value->getBindings()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$bindingNames = [];
|
||||
|
||||
foreach ($bindings as $key => $binding) {
|
||||
[$bindingValue, $bindingId, $used, $bindingType, $file] = $binding->getValues();
|
||||
if ($used) {
|
||||
$this->usedBindings[$bindingId ?? ''] = true;
|
||||
unset($this->unusedBindings[$bindingId ?? '']);
|
||||
} elseif (!isset($this->usedBindings[$bindingId ?? ''])) {
|
||||
$this->unusedBindings[$bindingId ?? ''] = [$key, $this->currentId, $bindingType, $file];
|
||||
}
|
||||
|
||||
if (preg_match('/^(?:(?:array|bool|float|int|string|iterable|([^ $]++)) )\$/', $key, $m)) {
|
||||
$bindingNames[substr($key, \strlen($m[0]))] = $binding;
|
||||
}
|
||||
|
||||
if (!isset($m[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_subclass_of($m[1], \UnitEnum::class)) {
|
||||
$bindingNames[substr($key, \strlen($m[0]))] = $binding;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, get_debug_type($bindingValue)));
|
||||
}
|
||||
}
|
||||
|
||||
if ($value->isAbstract()) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$calls = $value->getMethodCalls();
|
||||
|
||||
try {
|
||||
if ($constructor = $this->getConstructor($value, false)) {
|
||||
$calls[] = [$constructor, $value->getArguments()];
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$this->errorMessages[] = $e->getMessage();
|
||||
$this->container->getDefinition($this->currentId)->addError($e->getMessage());
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
foreach ($calls as $i => $call) {
|
||||
[$method, $arguments] = $call;
|
||||
|
||||
if ($method instanceof \ReflectionFunctionAbstract) {
|
||||
$reflectionMethod = $method;
|
||||
} else {
|
||||
try {
|
||||
$reflectionMethod = $this->getReflectionMethod($value, $method);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($value->getFactory()) {
|
||||
continue;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$names = [];
|
||||
|
||||
foreach ($reflectionMethod->getParameters() as $key => $parameter) {
|
||||
$names[$key] = $parameter->name;
|
||||
|
||||
if (\array_key_exists($key, $arguments) && '' !== $arguments[$key] && !$arguments[$key] instanceof AbstractArgument) {
|
||||
continue;
|
||||
}
|
||||
if (\array_key_exists($parameter->name, $arguments) && '' !== $arguments[$parameter->name] && !$arguments[$parameter->name] instanceof AbstractArgument) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
$value->isAutowired()
|
||||
&& !$value->hasTag('container.ignore_attributes')
|
||||
&& $parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$typeHint = ltrim(ProxyHelper::exportType($parameter) ?? '', '?');
|
||||
|
||||
$name = Target::parseName($parameter, parsedName: $parsedName);
|
||||
|
||||
if ($typeHint && (
|
||||
\array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$name, $bindings)
|
||||
|| \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$parsedName, $bindings)
|
||||
|| ($name !== $parameter->name && \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$parameter->name, $bindings))
|
||||
)) {
|
||||
$arguments[$key] = $this->getBindingValue($bindings[$k]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\array_key_exists($k = '$'.$name, $bindings)
|
||||
|| \array_key_exists($k = '$'.$parsedName, $bindings)
|
||||
|| ($name !== $parameter->name && \array_key_exists($k = '$'.$parameter->name, $bindings))
|
||||
) {
|
||||
$arguments[$key] = $this->getBindingValue($bindings[$k]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($typeHint && '\\' === $typeHint[0] && isset($bindings[$typeHint = substr($typeHint, 1)])) {
|
||||
$arguments[$key] = $this->getBindingValue($bindings[$typeHint]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null !== $binding = $bindingNames[$name] ?? $bindingNames[$parsedName] ?? $bindingNames[$parameter->name] ?? null) {
|
||||
$bindingKey = array_search($binding, $bindings, true);
|
||||
$argumentType = substr($bindingKey, 0, strpos($bindingKey, ' '));
|
||||
$this->errorMessages[] = \sprintf('Did you forget to add the type "%s" to argument "$%s" of method "%s::%s()"?', $argumentType, $parameter->name, $reflectionMethod->class, $reflectionMethod->name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($names as $key => $name) {
|
||||
if (\array_key_exists($name, $arguments) && (0 === $key || \array_key_exists($key - 1, $arguments))) {
|
||||
if (!\array_key_exists($key, $arguments)) {
|
||||
$arguments[$key] = $arguments[$name];
|
||||
}
|
||||
unset($arguments[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($arguments !== $call[1]) {
|
||||
ksort($arguments, \SORT_NATURAL);
|
||||
$calls[$i][1] = $arguments;
|
||||
}
|
||||
}
|
||||
|
||||
if ($constructor) {
|
||||
[, $arguments] = array_pop($calls);
|
||||
|
||||
if ($arguments !== $value->getArguments()) {
|
||||
$value->setArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
if ($calls !== $value->getMethodCalls()) {
|
||||
$value->setMethodCalls($calls);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
private function getBindingValue(BoundArgument $binding): mixed
|
||||
{
|
||||
[$bindingValue, $bindingId] = $binding->getValues();
|
||||
|
||||
$this->usedBindings[$bindingId ?? ''] = true;
|
||||
unset($this->unusedBindings[$bindingId ?? '']);
|
||||
|
||||
return $bindingValue;
|
||||
}
|
||||
}
|
||||
201
backend/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php
vendored
Normal file
201
backend/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\ExceptionInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
|
||||
/**
|
||||
* This replaces all ChildDefinition instances with their equivalent fully
|
||||
* merged Definition instance.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $currentPath;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
if ($isRoot) {
|
||||
// yes, we are specifically fetching the definition from the
|
||||
// container to ensure we are not operating on stale data
|
||||
$value = $this->container->getDefinition($this->currentId);
|
||||
}
|
||||
if ($value instanceof ChildDefinition) {
|
||||
$this->currentPath = [];
|
||||
$value = $this->resolveDefinition($value);
|
||||
if ($isRoot) {
|
||||
$this->container->setDefinition($this->currentId, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the definition.
|
||||
*
|
||||
* @throws RuntimeException When the definition is invalid
|
||||
*/
|
||||
private function resolveDefinition(ChildDefinition $definition): Definition
|
||||
{
|
||||
try {
|
||||
return $this->doResolveDefinition($definition);
|
||||
} catch (ServiceCircularReferenceException $e) {
|
||||
throw $e;
|
||||
} catch (ExceptionInterface $e) {
|
||||
$r = new \ReflectionProperty($e, 'message');
|
||||
$r->setValue($e, \sprintf('Service "%s": %s', $this->currentId, $e->getMessage()));
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function doResolveDefinition(ChildDefinition $definition): Definition
|
||||
{
|
||||
if (!$this->container->has($parent = $definition->getParent())) {
|
||||
throw new RuntimeException(\sprintf('Parent definition "%s" does not exist.', $parent));
|
||||
}
|
||||
|
||||
$searchKey = array_search($parent, $this->currentPath);
|
||||
$this->currentPath[] = $parent;
|
||||
|
||||
if (false !== $searchKey) {
|
||||
throw new ServiceCircularReferenceException($parent, \array_slice($this->currentPath, $searchKey));
|
||||
}
|
||||
|
||||
$parentDef = $this->container->findDefinition($parent);
|
||||
if ($parentDef instanceof ChildDefinition) {
|
||||
$id = $this->currentId;
|
||||
$this->currentId = $parent;
|
||||
$parentDef = $this->resolveDefinition($parentDef);
|
||||
$this->container->setDefinition($parent, $parentDef);
|
||||
$this->currentId = $id;
|
||||
}
|
||||
|
||||
$this->container->log($this, \sprintf('Resolving inheritance for "%s" (parent: %s).', $this->currentId, $parent));
|
||||
$def = new Definition();
|
||||
|
||||
// merge in parent definition
|
||||
// purposely ignored attributes: abstract, shared, tags, autoconfigured
|
||||
$def->setClass($parentDef->getClass());
|
||||
$def->setArguments($parentDef->getArguments());
|
||||
$def->setMethodCalls($parentDef->getMethodCalls());
|
||||
$def->setProperties($parentDef->getProperties());
|
||||
if ($parentDef->isDeprecated()) {
|
||||
$deprecation = $parentDef->getDeprecation('%service_id%');
|
||||
$def->setDeprecated($deprecation['package'], $deprecation['version'], $deprecation['message']);
|
||||
}
|
||||
$def->setFactory($parentDef->getFactory());
|
||||
$def->setConfigurator($parentDef->getConfigurator());
|
||||
$def->setFile($parentDef->getFile());
|
||||
$def->setPublic($parentDef->isPublic());
|
||||
$def->setLazy($parentDef->isLazy());
|
||||
$def->setAutowired($parentDef->isAutowired());
|
||||
$def->setChanges($parentDef->getChanges());
|
||||
|
||||
$def->setBindings($definition->getBindings() + $parentDef->getBindings());
|
||||
|
||||
$def->setSynthetic($definition->isSynthetic());
|
||||
|
||||
// overwrite with values specified in the decorator
|
||||
$changes = $definition->getChanges();
|
||||
if (isset($changes['class'])) {
|
||||
$def->setClass($definition->getClass());
|
||||
}
|
||||
if (isset($changes['factory'])) {
|
||||
$def->setFactory($definition->getFactory());
|
||||
}
|
||||
if (isset($changes['configurator'])) {
|
||||
$def->setConfigurator($definition->getConfigurator());
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$def->setFile($definition->getFile());
|
||||
}
|
||||
if (isset($changes['public'])) {
|
||||
$def->setPublic($definition->isPublic());
|
||||
} else {
|
||||
$def->setPublic($parentDef->isPublic());
|
||||
}
|
||||
if (isset($changes['lazy'])) {
|
||||
$def->setLazy($definition->isLazy());
|
||||
}
|
||||
if (isset($changes['deprecated']) && $definition->isDeprecated()) {
|
||||
$deprecation = $definition->getDeprecation('%service_id%');
|
||||
$def->setDeprecated($deprecation['package'], $deprecation['version'], $deprecation['message']);
|
||||
}
|
||||
if (isset($changes['autowired'])) {
|
||||
$def->setAutowired($definition->isAutowired());
|
||||
}
|
||||
if (isset($changes['shared'])) {
|
||||
$def->setShared($definition->isShared());
|
||||
}
|
||||
if (isset($changes['decorated_service'])) {
|
||||
$decoratedService = $definition->getDecoratedService();
|
||||
if (null === $decoratedService) {
|
||||
$def->setDecoratedService($decoratedService);
|
||||
} else {
|
||||
$def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2], $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
// merge arguments
|
||||
foreach ($definition->getArguments() as $k => $v) {
|
||||
if (is_numeric($k)) {
|
||||
$def->addArgument($v);
|
||||
} elseif (str_starts_with($k, 'index_')) {
|
||||
$def->replaceArgument((int) substr($k, \strlen('index_')), $v);
|
||||
} else {
|
||||
$def->setArgument($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
// merge properties
|
||||
foreach ($definition->getProperties() as $k => $v) {
|
||||
$def->setProperty($k, $v);
|
||||
}
|
||||
|
||||
// append method calls
|
||||
if ($calls = $definition->getMethodCalls()) {
|
||||
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
|
||||
}
|
||||
|
||||
$def->addError($parentDef);
|
||||
$def->addError($definition);
|
||||
|
||||
// these attributes are always taken from the child
|
||||
$def->setAbstract($definition->isAbstract());
|
||||
$def->setTags($definition->getTags());
|
||||
// autoconfigure is never taken from parent (on purpose)
|
||||
// and it's not legal on an instanceof
|
||||
$def->setAutoconfigured($definition->isAutoconfigured());
|
||||
|
||||
if (!$def->hasTag('proxy')) {
|
||||
foreach ($parentDef->getTag('proxy') as $v) {
|
||||
$def->addTag('proxy', $v);
|
||||
}
|
||||
}
|
||||
|
||||
return $def;
|
||||
}
|
||||
}
|
||||
46
backend/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php
vendored
Normal file
46
backend/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveClassPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isSynthetic()
|
||||
|| $definition->hasErrors()
|
||||
|| null !== $definition->getClass()
|
||||
|| !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $id)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if ($container->getReflectionClass($id, false)) {
|
||||
$definition->setClass($id);
|
||||
continue;
|
||||
}
|
||||
if ($definition instanceof ChildDefinition) {
|
||||
throw new InvalidArgumentException(\sprintf('Service definition "%s" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.', $id));
|
||||
}
|
||||
|
||||
trigger_deprecation('symfony/dependency-injection', '7.4', 'Service id "%s" looks like a FQCN but no corresponding class or interface exists. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class or interface.', $id);
|
||||
// throw new InvalidArgumentException(\sprintf('Service id "%s" looks like a FQCN but no corresponding class or interface exists. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class or interface.'), $id);
|
||||
$definition->setClass($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
backend/vendor/symfony/dependency-injection/Compiler/ResolveDecoratorStackPass.php
vendored
Normal file
120
backend/vendor/symfony/dependency-injection/Compiler/ResolveDecoratorStackPass.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveDecoratorStackPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$stacks = [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds('container.stack') as $id => $tags) {
|
||||
$definition = $container->getDefinition($id);
|
||||
|
||||
if (!$definition instanceof ChildDefinition) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": only definitions with a "parent" can have the "container.stack" tag.', $id));
|
||||
}
|
||||
|
||||
if (!$stack = $definition->getArguments()) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": the stack of decorators is empty.', $id));
|
||||
}
|
||||
|
||||
$stacks[$id] = $stack;
|
||||
}
|
||||
|
||||
if (!$stacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resolvedDefinitions = [];
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if (!isset($stacks[$id])) {
|
||||
$resolvedDefinitions[$id] = $definition;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (array_reverse($this->resolveStack($stacks, [$id]), true) as $k => $v) {
|
||||
$resolvedDefinitions[$k] = $v;
|
||||
}
|
||||
|
||||
$alias = $container->setAlias($id, $k);
|
||||
|
||||
if ($definition->getChanges()['public'] ?? false) {
|
||||
$alias->setPublic($definition->isPublic());
|
||||
}
|
||||
|
||||
if ($definition->isDeprecated()) {
|
||||
$alias->setDeprecated(...array_values($definition->getDeprecation('%alias_id%')));
|
||||
}
|
||||
}
|
||||
|
||||
$container->setDefinitions($resolvedDefinitions);
|
||||
}
|
||||
|
||||
private function resolveStack(array $stacks, array $path): array
|
||||
{
|
||||
$definitions = [];
|
||||
$id = end($path);
|
||||
$prefix = '.'.$id.'.';
|
||||
|
||||
if (!isset($stacks[$id])) {
|
||||
return [$id => new ChildDefinition($id)];
|
||||
}
|
||||
|
||||
if (key($path) !== $searchKey = array_search($id, $path)) {
|
||||
throw new ServiceCircularReferenceException($id, \array_slice($path, $searchKey));
|
||||
}
|
||||
|
||||
foreach ($stacks[$id] as $k => $definition) {
|
||||
if ($definition instanceof ChildDefinition && isset($stacks[$definition->getParent()])) {
|
||||
$path[] = $definition->getParent();
|
||||
$definition = unserialize(serialize($definition)); // deep clone
|
||||
} elseif ($definition instanceof Definition) {
|
||||
$definitions[$decoratedId = $prefix.$k] = $definition;
|
||||
continue;
|
||||
} elseif ($definition instanceof Reference || $definition instanceof Alias) {
|
||||
$path[] = (string) $definition;
|
||||
} else {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": unexpected value of type "%s" found in the stack of decorators.', $id, get_debug_type($definition)));
|
||||
}
|
||||
|
||||
$p = $prefix.$k;
|
||||
|
||||
foreach ($this->resolveStack($stacks, $path) as $k => $v) {
|
||||
$definitions[$decoratedId = $p.$k] = $definition instanceof ChildDefinition ? $definition->setParent($k) : new ChildDefinition($k);
|
||||
$definition = null;
|
||||
}
|
||||
array_pop($path);
|
||||
}
|
||||
|
||||
if (1 === \count($path)) {
|
||||
foreach ($definitions as $k => $definition) {
|
||||
$definition->setPublic(false)->setTags([])->setDecoratedService($decoratedId);
|
||||
}
|
||||
$definition->setDecoratedService(null);
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
}
|
||||
56
backend/vendor/symfony/dependency-injection/Compiler/ResolveEnvPlaceholdersPass.php
vendored
Normal file
56
backend/vendor/symfony/dependency-injection/Compiler/ResolveEnvPlaceholdersPass.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* Replaces env var placeholders by their current values.
|
||||
*/
|
||||
class ResolveEnvPlaceholdersPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = false;
|
||||
|
||||
/**
|
||||
* @param string|true|null $format A sprintf() format returning the replacement for each env var name or
|
||||
* null to resolve back to the original "%env(VAR)%" format or
|
||||
* true to resolve to the actual values of the referenced env vars
|
||||
*/
|
||||
public function __construct(
|
||||
private string|bool|null $format = true,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (\is_string($value)) {
|
||||
return $this->container->resolveEnvPlaceholders($value, $this->format);
|
||||
}
|
||||
if ($value instanceof Definition) {
|
||||
$changes = $value->getChanges();
|
||||
if (isset($changes['class'])) {
|
||||
$value->setClass($this->container->resolveEnvPlaceholders($value->getClass(), $this->format));
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$value->setFile($this->container->resolveEnvPlaceholders($value->getFile(), $this->format));
|
||||
}
|
||||
}
|
||||
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if ($value && \is_array($value) && !$isRoot) {
|
||||
$value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), $this->format), $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
37
backend/vendor/symfony/dependency-injection/Compiler/ResolveFactoryClassPass.php
vendored
Normal file
37
backend/vendor/symfony/dependency-injection/Compiler/ResolveFactoryClassPass.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*/
|
||||
class ResolveFactoryClassPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Definition && \is_array($factory = $value->getFactory()) && null === $factory[0]) {
|
||||
if (null === $class = $value->getClass()) {
|
||||
throw new RuntimeException(\sprintf('The "%s" service is defined to be created by a factory, but is missing the factory class. Did you forget to define the factory or service class?', $this->currentId));
|
||||
}
|
||||
|
||||
$factory[0] = $class;
|
||||
$value->setFactory($factory);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
76
backend/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php
vendored
Normal file
76
backend/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Propagate "container.hot_path" tags to referenced services.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveHotPathPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $resolvedIds = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
try {
|
||||
parent::process($container);
|
||||
$container->getDefinition('service_container')->clearTag('container.hot_path');
|
||||
} finally {
|
||||
$this->resolvedIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof Definition && $isRoot) {
|
||||
if ($value->isDeprecated()) {
|
||||
return $value->clearTag('container.hot_path');
|
||||
}
|
||||
|
||||
$this->resolvedIds[$this->currentId ?? ''] = true;
|
||||
|
||||
if (!$value->hasTag('container.hot_path')) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->hasDefinition($id = (string) $value)) {
|
||||
$definition = $this->container->getDefinition($id);
|
||||
|
||||
if ($definition->isDeprecated() || $definition->hasTag('container.hot_path')) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$definition->addTag('container.hot_path');
|
||||
|
||||
if (isset($this->resolvedIds[$id])) {
|
||||
parent::processValue($definition, false);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
180
backend/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php
vendored
Normal file
180
backend/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Applies instanceof conditionals to definitions.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveInstanceofConditionalsPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($container->getAutoconfiguredInstanceof() as $interface => $definition) {
|
||||
if ($definition->getArguments()) {
|
||||
throw new InvalidArgumentException(\sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface));
|
||||
}
|
||||
}
|
||||
|
||||
$tagsToKeep = [];
|
||||
|
||||
if ($container->hasParameter('container.behavior_describing_tags')) {
|
||||
$tagsToKeep = $container->getParameter('container.behavior_describing_tags');
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$container->setDefinition($id, $this->processDefinition($container, $id, $definition, $tagsToKeep));
|
||||
}
|
||||
|
||||
if ($container->hasParameter('container.behavior_describing_tags')) {
|
||||
$container->getParameterBag()->remove('container.behavior_describing_tags');
|
||||
}
|
||||
}
|
||||
|
||||
private function processDefinition(ContainerBuilder $container, string $id, Definition $definition, array $tagsToKeep): Definition
|
||||
{
|
||||
$instanceofConditionals = $definition->getInstanceofConditionals();
|
||||
$autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : [];
|
||||
if (!$instanceofConditionals && !$autoconfiguredInstanceof) {
|
||||
return $definition;
|
||||
}
|
||||
|
||||
if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
|
||||
return $definition;
|
||||
}
|
||||
|
||||
$conditionals = $this->mergeConditionals($autoconfiguredInstanceof, $instanceofConditionals, $container);
|
||||
|
||||
$definition->setInstanceofConditionals([]);
|
||||
$shared = null;
|
||||
$instanceofTags = [];
|
||||
$instanceofCalls = [];
|
||||
$instanceofBindings = [];
|
||||
$reflectionClass = null;
|
||||
$parent = $definition instanceof ChildDefinition ? $definition->getParent() : null;
|
||||
|
||||
foreach ($conditionals as $interface => $instanceofDefs) {
|
||||
if ($interface !== $class && !($reflectionClass ??= $container->getReflectionClass($class, false) ?: false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($interface !== $class && !is_subclass_of($class, $interface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($instanceofDefs as $key => $instanceofDef) {
|
||||
/** @var ChildDefinition $instanceofDef */
|
||||
$instanceofDef = clone $instanceofDef;
|
||||
$instanceofDef->setAbstract(true)->setParent($parent ?: '.abstract.instanceof.'.$id);
|
||||
$parent = '.instanceof.'.$interface.'.'.$key.'.'.$id;
|
||||
$container->setDefinition($parent, $instanceofDef);
|
||||
$instanceofTags[] = [$interface, $instanceofDef->getTags()];
|
||||
$instanceofBindings = $instanceofDef->getBindings() + $instanceofBindings;
|
||||
|
||||
foreach ($instanceofDef->getMethodCalls() as $methodCall) {
|
||||
$instanceofCalls[] = $methodCall;
|
||||
}
|
||||
|
||||
$instanceofDef->setTags([]);
|
||||
$instanceofDef->setMethodCalls([]);
|
||||
$instanceofDef->setBindings([]);
|
||||
|
||||
if (isset($instanceofDef->getChanges()['shared'])) {
|
||||
$shared = $instanceofDef->isShared();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
$bindings = $definition->getBindings();
|
||||
$abstract = $container->setDefinition('.abstract.instanceof.'.$id, $definition);
|
||||
$definition->setBindings([]);
|
||||
$definition = serialize($definition);
|
||||
|
||||
if (Definition::class === $abstract::class) {
|
||||
// cast Definition to ChildDefinition
|
||||
$definition = substr_replace($definition, '53', 2, 2);
|
||||
$definition = substr_replace($definition, 'Child', 44, 0);
|
||||
}
|
||||
/** @var ChildDefinition $definition */
|
||||
$definition = unserialize($definition);
|
||||
$definition->setParent($parent);
|
||||
|
||||
if (null !== $shared && !isset($definition->getChanges()['shared'])) {
|
||||
$definition->setShared($shared);
|
||||
}
|
||||
|
||||
// Don't add tags to service decorators
|
||||
$i = \count($instanceofTags);
|
||||
while (0 <= --$i) {
|
||||
[$interface, $tags] = $instanceofTags[$i];
|
||||
foreach ($tags as $k => $v) {
|
||||
if (null === $definition->getDecoratedService() || $interface === $definition->getClass() || \in_array($k, $tagsToKeep, true)) {
|
||||
foreach ($v as $v) {
|
||||
if ($definition->hasTag($k) && \in_array($v, $definition->getTag($k), true)) {
|
||||
continue;
|
||||
}
|
||||
$definition->addTag($k, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls()));
|
||||
$definition->setBindings($bindings + $instanceofBindings);
|
||||
|
||||
// reset fields with "merge" behavior
|
||||
$abstract
|
||||
->setBindings([])
|
||||
->setArguments([])
|
||||
->setMethodCalls([])
|
||||
->setDecoratedService(null)
|
||||
->setTags([])
|
||||
->setAbstract(true);
|
||||
}
|
||||
|
||||
if ($definition->isSynthetic()) {
|
||||
// Ignore container.excluded tag on synthetic services
|
||||
$definition->clearTag('container.excluded');
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container): array
|
||||
{
|
||||
// make each value an array of ChildDefinition
|
||||
$conditionals = array_map(fn ($childDef) => [$childDef], $autoconfiguredInstanceof);
|
||||
|
||||
foreach ($instanceofConditionals as $interface => $instanceofDef) {
|
||||
// make sure the interface/class exists (but don't validate automaticInstanceofConditionals)
|
||||
if (!$container->getReflectionClass($interface)) {
|
||||
throw new RuntimeException(\sprintf('"%s" is set as an "instanceof" conditional, but it does not exist.', $interface));
|
||||
}
|
||||
|
||||
if (!isset($autoconfiguredInstanceof[$interface])) {
|
||||
$conditionals[$interface] = [];
|
||||
}
|
||||
|
||||
$conditionals[$interface][] = $instanceofDef;
|
||||
}
|
||||
|
||||
return $conditionals;
|
||||
}
|
||||
}
|
||||
134
backend/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php
vendored
Normal file
134
backend/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
/**
|
||||
* Emulates the invalid behavior if the reference is not found within the
|
||||
* container.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveInvalidReferencesPass implements CompilerPassInterface
|
||||
{
|
||||
private ContainerBuilder $container;
|
||||
private RuntimeException $signalingException;
|
||||
private string $currentId;
|
||||
|
||||
/**
|
||||
* Process the ContainerBuilder to resolve invalid references.
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->signalingException = new RuntimeException('Invalid reference.');
|
||||
|
||||
try {
|
||||
foreach ($container->getDefinitions() as $this->currentId => $definition) {
|
||||
$this->processValue($definition);
|
||||
}
|
||||
} finally {
|
||||
unset($this->container, $this->signalingException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes arguments to determine invalid references.
|
||||
*
|
||||
* @throws RuntimeException When an invalid reference is found
|
||||
*/
|
||||
private function processValue(mixed $value, int $rootLevel = 0, int $level = 0): mixed
|
||||
{
|
||||
if ($value instanceof ServiceClosureArgument) {
|
||||
$value->setValues($this->processValue($value->getValues(), 1, 1));
|
||||
} elseif ($value instanceof ArgumentInterface) {
|
||||
$value->setValues($this->processValue($value->getValues(), $rootLevel, 1 + $level));
|
||||
} elseif ($value instanceof Definition) {
|
||||
if ($value->isSynthetic() || $value->isAbstract() || $value->hasTag('container.excluded')) {
|
||||
return $value;
|
||||
}
|
||||
$value->setArguments($this->processValue($value->getArguments(), 0));
|
||||
$value->setProperties($this->processValue($value->getProperties(), 1));
|
||||
$value->setMethodCalls($this->processValue($value->getMethodCalls(), 2));
|
||||
} elseif (\is_array($value)) {
|
||||
$i = 0;
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
try {
|
||||
if (false !== $i && $k !== $i++) {
|
||||
$i = false;
|
||||
}
|
||||
if ($v !== $processedValue = $this->processValue($v, $rootLevel, 1 + $level)) {
|
||||
$value[$k] = $processedValue;
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
if ($rootLevel < $level || ($rootLevel && !$level)) {
|
||||
unset($value[$k]);
|
||||
} elseif ($rootLevel) {
|
||||
throw $e;
|
||||
} else {
|
||||
$value[$k] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure numerically indexed arguments have sequential numeric keys.
|
||||
if (false !== $i) {
|
||||
$value = array_values($value);
|
||||
}
|
||||
} elseif ($value instanceof Reference) {
|
||||
if ($this->container->hasDefinition($id = (string) $value) ? !$this->container->getDefinition($id)->hasTag('container.excluded') : $this->container->hasAlias($id)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$currentDefinition = $this->container->getDefinition($this->currentId);
|
||||
|
||||
// resolve decorated service behavior depending on decorator service
|
||||
if ($currentDefinition->innerServiceId === $id && ContainerInterface::NULL_ON_INVALID_REFERENCE === $currentDefinition->decorationOnInvalid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$invalidBehavior = $value->getInvalidBehavior();
|
||||
|
||||
if (ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior && $value instanceof TypedReference && !$this->container->has($id)) {
|
||||
$e = new ServiceNotFoundException($id, $this->currentId);
|
||||
|
||||
// since the error message varies by $id and $this->currentId, so should the id of the dummy errored definition
|
||||
$this->container->register($id = \sprintf('.errored.%s.%s', $this->currentId, $id), $value->getType())
|
||||
->addError($e->getMessage());
|
||||
|
||||
return new TypedReference($id, $value->getType(), $value->getInvalidBehavior());
|
||||
}
|
||||
|
||||
// resolve invalid behavior
|
||||
if (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
$value = null;
|
||||
} elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
if (0 < $level || $rootLevel) {
|
||||
throw $this->signalingException;
|
||||
}
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
137
backend/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php
vendored
Normal file
137
backend/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* Resolves named arguments to their corresponding numeric index.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class ResolveNamedArgumentsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof AbstractArgument && $value->getText().'.' === $value->getTextWithContext()) {
|
||||
$value->setContext(\sprintf('A value found in service "%s"', $this->currentId));
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$calls = $value->getMethodCalls();
|
||||
$calls[] = ['__construct', $value->getArguments()];
|
||||
|
||||
foreach ($calls as $i => $call) {
|
||||
[$method, $arguments] = $call;
|
||||
$parameters = null;
|
||||
$resolvedKeys = [];
|
||||
$resolvedArguments = [];
|
||||
|
||||
foreach ($arguments as $key => $argument) {
|
||||
if ($argument instanceof AbstractArgument && $argument->getText().'.' === $argument->getTextWithContext()) {
|
||||
$argument->setContext(\sprintf('Argument '.(\is_int($key) ? 1 + $key : '"%3$s"').' of '.('__construct' === $method ? 'service "%s"' : 'method call "%s::%s()"'), $this->currentId, $method, $key));
|
||||
}
|
||||
|
||||
if (\is_int($key)) {
|
||||
$resolvedKeys[$key] = $key;
|
||||
$resolvedArguments[$key] = $argument;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $parameters) {
|
||||
$r = $this->getReflectionMethod($value, $method);
|
||||
$class = $r instanceof \ReflectionMethod ? $r->class : $this->currentId;
|
||||
$method = $r->getName();
|
||||
$parameters = $r->getParameters();
|
||||
}
|
||||
|
||||
if (isset($key[0]) && '$' !== $key[0] && !class_exists($key) && !interface_exists($key, false)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": did you forget to add the "$" prefix to argument "%s"?', $this->currentId, $key));
|
||||
}
|
||||
|
||||
if (isset($key[0]) && '$' === $key[0]) {
|
||||
foreach ($parameters as $j => $p) {
|
||||
if ($key === '$'.$p->name) {
|
||||
if ($p->isVariadic() && \is_array($argument)) {
|
||||
foreach ($argument as $variadicArgument) {
|
||||
$resolvedKeys[$j] = $j;
|
||||
$resolvedArguments[$j++] = $variadicArgument;
|
||||
}
|
||||
} else {
|
||||
$resolvedKeys[$j] = $p->name;
|
||||
$resolvedArguments[$j] = $argument;
|
||||
}
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": method "%s()" has no argument named "%s". Check your service definition.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method, $key));
|
||||
}
|
||||
|
||||
if (null !== $argument && !$argument instanceof Reference && !$argument instanceof Definition) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": the value of argument "%s" of method "%s()" must be null, an instance of "%s" or an instance of "%s", "%s" given.', $this->currentId, $key, $class !== $this->currentId ? $class.'::'.$method : $method, Reference::class, Definition::class, get_debug_type($argument)));
|
||||
}
|
||||
|
||||
$typeFound = false;
|
||||
foreach ($parameters as $j => $p) {
|
||||
if (!\array_key_exists($j, $resolvedArguments) && ProxyHelper::exportType($p, true) === $key) {
|
||||
$resolvedKeys[$j] = $p->name;
|
||||
$resolvedArguments[$j] = $argument;
|
||||
$typeFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$typeFound) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid service "%s": method "%s()" has no argument type-hinted as "%s". Check your service definition.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method, $key));
|
||||
}
|
||||
}
|
||||
|
||||
if ($resolvedArguments !== $call[1]) {
|
||||
ksort($resolvedArguments);
|
||||
|
||||
if (!$value->isAutowired() && !array_is_list($resolvedArguments)) {
|
||||
ksort($resolvedKeys);
|
||||
$resolvedArguments = array_combine($resolvedKeys, $resolvedArguments);
|
||||
}
|
||||
|
||||
$calls[$i][1] = $resolvedArguments;
|
||||
}
|
||||
}
|
||||
|
||||
[, $arguments] = array_pop($calls);
|
||||
|
||||
if ($arguments !== $value->getArguments()) {
|
||||
$value->setArguments($arguments);
|
||||
}
|
||||
if ($calls !== $value->getMethodCalls()) {
|
||||
$value->setMethodCalls($calls);
|
||||
}
|
||||
|
||||
foreach ($value->getProperties() as $key => $argument) {
|
||||
if ($argument instanceof AbstractArgument && $argument->getText().'.' === $argument->getTextWithContext()) {
|
||||
$argument->setContext(\sprintf('Property "%s" of service "%s"', $key, $this->currentId));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
90
backend/vendor/symfony/dependency-injection/Compiler/ResolveNoPreloadPass.php
vendored
Normal file
90
backend/vendor/symfony/dependency-injection/Compiler/ResolveNoPreloadPass.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Propagate the "container.no_preload" tag.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveNoPreloadPass extends AbstractRecursivePass
|
||||
{
|
||||
private const DO_PRELOAD_TAG = '.container.do_preload';
|
||||
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private array $resolvedIds = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
try {
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isPublic() && !isset($this->resolvedIds[$id])) {
|
||||
$this->resolvedIds[$id] = true;
|
||||
$this->processValue($definition, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $alias) {
|
||||
if ($alias->isPublic() && !isset($this->resolvedIds[$id = (string) $alias]) && $container->hasDefinition($id)) {
|
||||
$this->resolvedIds[$id] = true;
|
||||
$this->processValue($container->getDefinition($id), true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$this->resolvedIds = [];
|
||||
$this->container = null;
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if ($definition->hasTag(self::DO_PRELOAD_TAG)) {
|
||||
$definition->clearTag(self::DO_PRELOAD_TAG);
|
||||
} elseif (!$definition->isDeprecated() && !$definition->hasErrors()) {
|
||||
$definition->addTag('container.no_preload');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->hasDefinition($id = (string) $value)) {
|
||||
$definition = $this->container->getDefinition($id);
|
||||
|
||||
if (!isset($this->resolvedIds[$id]) && $definition->isPrivate()) {
|
||||
$this->resolvedIds[$id] = true;
|
||||
$this->processValue($definition, true);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if ($value->hasTag('container.no_preload') || $value->isDeprecated() || $value->hasErrors()) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($isRoot) {
|
||||
$value->addTag(self::DO_PRELOAD_TAG);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
102
backend/vendor/symfony/dependency-injection/Compiler/ResolveParameterPlaceHoldersPass.php
vendored
Normal file
102
backend/vendor/symfony/dependency-injection/Compiler/ResolveParameterPlaceHoldersPass.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
/**
|
||||
* Resolves all parameter placeholders "%somevalue%" to their real values.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveParameterPlaceHoldersPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = false;
|
||||
|
||||
private ParameterBagInterface $bag;
|
||||
|
||||
public function __construct(
|
||||
private bool $resolveArrays = true,
|
||||
private bool $throwOnResolveException = true,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ParameterNotFoundException
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->bag = $container->getParameterBag();
|
||||
|
||||
try {
|
||||
parent::process($container);
|
||||
|
||||
$aliases = [];
|
||||
foreach ($container->getAliases() as $name => $target) {
|
||||
$this->currentId = $name;
|
||||
$aliases[$this->bag->resolveValue($name)] = $target;
|
||||
}
|
||||
$container->setAliases($aliases);
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceId($this->currentId);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->bag->resolve();
|
||||
unset($this->bag);
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (\is_string($value)) {
|
||||
try {
|
||||
$v = $this->bag->resolveValue($value);
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
if ($this->throwOnResolveException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$v = null;
|
||||
$this->container->getDefinition($this->currentId)->addError($e->getMessage());
|
||||
}
|
||||
|
||||
return $this->resolveArrays || !$v || !\is_array($v) ? $v : $value;
|
||||
}
|
||||
if ($value instanceof Definition) {
|
||||
$value->setBindings($this->processValue($value->getBindings()));
|
||||
$changes = $value->getChanges();
|
||||
if (isset($changes['class'])) {
|
||||
$value->setClass($this->bag->resolveValue($value->getClass()));
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$value->setFile($this->bag->resolveValue($value->getFile()));
|
||||
}
|
||||
$tags = $value->getTags();
|
||||
if (isset($tags['proxy'])) {
|
||||
$tags['proxy'] = $this->bag->resolveValue($tags['proxy']);
|
||||
$value->setTags($tags);
|
||||
}
|
||||
}
|
||||
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if ($value && \is_array($value)) {
|
||||
$value = array_combine($this->bag->resolveValue(array_keys($value)), $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
84
backend/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php
vendored
Normal file
84
backend/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Replaces all references to aliases with references to the actual service.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveReferencesToAliasesPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
parent::process($container);
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$aliasId = (string) $alias;
|
||||
$this->currentId = $id;
|
||||
|
||||
if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) {
|
||||
$newAlias = $container->setAlias($id, $defId)->setPublic($alias->isPublic());
|
||||
|
||||
if ($alias->isDeprecated()) {
|
||||
$newAlias->setDeprecated(...array_values($alias->getDeprecation('%alias_id%')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Reference) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$defId = $this->getDefinitionId($id = (string) $value, $this->container);
|
||||
|
||||
return $defId !== $id ? new Reference($defId, $value->getInvalidBehavior()) : $value;
|
||||
}
|
||||
|
||||
private function getDefinitionId(string $id, ContainerBuilder $container): string
|
||||
{
|
||||
if (!$container->hasAlias($id)) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
$alias = $container->getAlias($id);
|
||||
|
||||
if ($alias->isDeprecated()) {
|
||||
$referencingDefinition = $container->hasDefinition($this->currentId) ? $container->getDefinition($this->currentId) : $container->getAlias($this->currentId);
|
||||
if (!$referencingDefinition->isDeprecated()) {
|
||||
$deprecation = $alias->getDeprecation($id);
|
||||
trigger_deprecation($deprecation['package'], $deprecation['version'], rtrim($deprecation['message'], '. ').'. It is being referenced by the "%s" '.($container->hasDefinition($this->currentId) ? 'service.' : 'alias.'), $this->currentId);
|
||||
}
|
||||
}
|
||||
|
||||
$seen = [];
|
||||
do {
|
||||
if (isset($seen[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id]));
|
||||
}
|
||||
|
||||
$seen[$id] = true;
|
||||
$id = (string) $container->getAlias($id);
|
||||
} while ($container->hasAlias($id));
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
54
backend/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php
vendored
Normal file
54
backend/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Compiler pass to inject their service locator to service subscribers.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ResolveServiceSubscribersPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private ?string $serviceLocator = null;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference && $this->serviceLocator && \in_array((string) $value, [ContainerInterface::class, ServiceProviderInterface::class], true)) {
|
||||
return new Reference($this->serviceLocator);
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$serviceLocator = $this->serviceLocator;
|
||||
$this->serviceLocator = null;
|
||||
|
||||
if ($value->hasTag('container.service_subscriber.locator')) {
|
||||
$this->serviceLocator = $value->getTag('container.service_subscriber.locator')[0]['id'];
|
||||
$value->clearTag('container.service_subscriber.locator');
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::processValue($value);
|
||||
} finally {
|
||||
$this->serviceLocator = $serviceLocator;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
backend/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php
vendored
Normal file
42
backend/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
|
||||
/**
|
||||
* Resolves all TaggedIteratorArgument arguments.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof TaggedIteratorArgument) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$exclude = $value->getExclude();
|
||||
if ($value->excludeSelf()) {
|
||||
$exclude[] = $this->currentId;
|
||||
}
|
||||
|
||||
$value->setValues($this->findAndSortTaggedServices($value, $this->container, $exclude));
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
140
backend/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
vendored
Normal file
140
backend/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
/**
|
||||
* Applies the "container.service_locator" tag by wrapping references into ServiceClosureArgument instances.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof ServiceLocatorArgument) {
|
||||
if ($value->getTaggedIteratorArgument()) {
|
||||
$value->setValues($this->findAndSortTaggedServices($value->getTaggedIteratorArgument(), $this->container));
|
||||
}
|
||||
|
||||
return self::register($this->container, $value->getValues());
|
||||
}
|
||||
|
||||
if ($value instanceof Definition) {
|
||||
$value->setBindings(parent::processValue($value->getBindings()));
|
||||
}
|
||||
|
||||
if (!$value instanceof Definition || !$value->hasTag('container.service_locator')) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if (!$value->getClass()) {
|
||||
$value->setClass(ServiceLocator::class);
|
||||
}
|
||||
|
||||
$values = $value->getArguments()[0] ?? null;
|
||||
$services = [];
|
||||
|
||||
if ($values instanceof TaggedIteratorArgument) {
|
||||
foreach ($this->findAndSortTaggedServices($values, $this->container) as $k => $v) {
|
||||
$services[$k] = new ServiceClosureArgument($v);
|
||||
}
|
||||
} elseif (!\is_array($values)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid definition for service "%s": an array of references is expected as first argument when the "container.service_locator" tag is set.', $this->currentId));
|
||||
} else {
|
||||
$i = 0;
|
||||
|
||||
foreach ($values as $k => $v) {
|
||||
if ($v instanceof ServiceClosureArgument) {
|
||||
$services[$k] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($i === $k) {
|
||||
if ($v instanceof Reference) {
|
||||
$k = (string) $v;
|
||||
}
|
||||
++$i;
|
||||
} elseif (\is_int($k)) {
|
||||
$i = null;
|
||||
}
|
||||
|
||||
$services[$k] = new ServiceClosureArgument($v);
|
||||
}
|
||||
if (\count($services) === $i) {
|
||||
ksort($services);
|
||||
}
|
||||
}
|
||||
|
||||
$value->setArgument(0, $services);
|
||||
|
||||
$id = '.service_locator.'.ContainerBuilder::hash($value);
|
||||
|
||||
if ($isRoot) {
|
||||
if ($id !== $this->currentId) {
|
||||
$this->container->setAlias($id, new Alias($this->currentId, false));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
$this->container->setDefinition($id, $value->setPublic(false));
|
||||
|
||||
return new Reference($id);
|
||||
}
|
||||
|
||||
public static function register(ContainerBuilder $container, array $map, ?string $callerId = null): Reference
|
||||
{
|
||||
foreach ($map as $k => $v) {
|
||||
$map[$k] = new ServiceClosureArgument($v);
|
||||
}
|
||||
|
||||
$locator = (new Definition(ServiceLocator::class))
|
||||
->addArgument($map)
|
||||
->addTag('container.service_locator');
|
||||
|
||||
if (null !== $callerId && $container->hasDefinition($callerId)) {
|
||||
$locator->setBindings($container->getDefinition($callerId)->getBindings());
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition($id = '.service_locator.'.ContainerBuilder::hash($locator))) {
|
||||
$container->setDefinition($id, $locator);
|
||||
}
|
||||
|
||||
if (null !== $callerId) {
|
||||
$locatorId = $id;
|
||||
// Locators are shared when they hold the exact same list of factories;
|
||||
// to have them specialized per consumer service, we use a cloning factory
|
||||
// to derivate customized instances from the prototype one.
|
||||
$container->register($id .= '.'.$callerId, ServiceLocator::class)
|
||||
->setFactory([new Reference($locatorId), 'withContext'])
|
||||
->addTag('container.service_locator_context', ['id' => $callerId])
|
||||
->addArgument($callerId)
|
||||
->addArgument(new Reference('service_container'));
|
||||
}
|
||||
|
||||
return new Reference($id);
|
||||
}
|
||||
}
|
||||
99
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php
vendored
Normal file
99
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* This is a directed graph of your services.
|
||||
*
|
||||
* This information can be used by your compiler passes instead of collecting
|
||||
* it themselves which improves performance quite a lot.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ServiceReferenceGraph
|
||||
{
|
||||
/**
|
||||
* @var ServiceReferenceGraphNode[]
|
||||
*/
|
||||
private array $nodes = [];
|
||||
|
||||
public function hasNode(string $id): bool
|
||||
{
|
||||
return isset($this->nodes[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node by identifier.
|
||||
*
|
||||
* @throws InvalidArgumentException if no node matches the supplied identifier
|
||||
*/
|
||||
public function getNode(string $id): ServiceReferenceGraphNode
|
||||
{
|
||||
if (!isset($this->nodes[$id])) {
|
||||
throw new InvalidArgumentException(\sprintf('There is no node with id "%s".', $id));
|
||||
}
|
||||
|
||||
return $this->nodes[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all nodes.
|
||||
*
|
||||
* @return ServiceReferenceGraphNode[]
|
||||
*/
|
||||
public function getNodes(): array
|
||||
{
|
||||
return $this->nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all nodes.
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
foreach ($this->nodes as $node) {
|
||||
$node->clear();
|
||||
}
|
||||
$this->nodes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects 2 nodes together in the Graph.
|
||||
*/
|
||||
public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, mixed $destValue = null, ?Reference $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false, bool $byMultiUseArgument = false): void
|
||||
{
|
||||
if (null === $sourceId || null === $destId) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceNode = $this->createNode($sourceId, $sourceValue);
|
||||
$destNode = $this->createNode($destId, $destValue);
|
||||
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak, $byConstructor, $byMultiUseArgument);
|
||||
|
||||
$sourceNode->addOutEdge($edge);
|
||||
$destNode->addInEdge($edge);
|
||||
}
|
||||
|
||||
private function createNode(string $id, mixed $value): ServiceReferenceGraphNode
|
||||
{
|
||||
if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) {
|
||||
return $this->nodes[$id];
|
||||
}
|
||||
|
||||
return $this->nodes[$id] = new ServiceReferenceGraphNode($id, $value);
|
||||
}
|
||||
}
|
||||
86
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php
vendored
Normal file
86
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
/**
|
||||
* Represents an edge in your service graph.
|
||||
*
|
||||
* Value is typically a reference.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceReferenceGraphEdge
|
||||
{
|
||||
public function __construct(
|
||||
private ServiceReferenceGraphNode $sourceNode,
|
||||
private ServiceReferenceGraphNode $destNode,
|
||||
private mixed $value = null,
|
||||
private bool $lazy = false,
|
||||
private bool $weak = false,
|
||||
private bool $byConstructor = false,
|
||||
private bool $byMultiUseArgument = false,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the edge.
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source node.
|
||||
*/
|
||||
public function getSourceNode(): ServiceReferenceGraphNode
|
||||
{
|
||||
return $this->sourceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the destination node.
|
||||
*/
|
||||
public function getDestNode(): ServiceReferenceGraphNode
|
||||
{
|
||||
return $this->destNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the edge is lazy, meaning it's a dependency not requiring direct instantiation.
|
||||
*/
|
||||
public function isLazy(): bool
|
||||
{
|
||||
return $this->lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the edge is weak, meaning it shouldn't prevent removing the target service.
|
||||
*/
|
||||
public function isWeak(): bool
|
||||
{
|
||||
return $this->weak;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the edge links with a constructor argument.
|
||||
*/
|
||||
public function isReferencedByConstructor(): bool
|
||||
{
|
||||
return $this->byConstructor;
|
||||
}
|
||||
|
||||
public function isFromMultiUseArgument(): bool
|
||||
{
|
||||
return $this->byMultiUseArgument;
|
||||
}
|
||||
}
|
||||
104
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php
vendored
Normal file
104
backend/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* Represents a node in your service graph.
|
||||
*
|
||||
* Value is typically a definition, or an alias.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceReferenceGraphNode
|
||||
{
|
||||
private array $inEdges = [];
|
||||
private array $outEdges = [];
|
||||
|
||||
public function __construct(
|
||||
private string $id,
|
||||
private mixed $value,
|
||||
) {
|
||||
}
|
||||
|
||||
public function addInEdge(ServiceReferenceGraphEdge $edge): void
|
||||
{
|
||||
$this->inEdges[] = $edge;
|
||||
}
|
||||
|
||||
public function addOutEdge(ServiceReferenceGraphEdge $edge): void
|
||||
{
|
||||
$this->outEdges[] = $edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of this node is an Alias.
|
||||
*/
|
||||
public function isAlias(): bool
|
||||
{
|
||||
return $this->value instanceof Alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of this node is a Definition.
|
||||
*/
|
||||
public function isDefinition(): bool
|
||||
{
|
||||
return $this->value instanceof Definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier.
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the in edges.
|
||||
*
|
||||
* @return ServiceReferenceGraphEdge[]
|
||||
*/
|
||||
public function getInEdges(): array
|
||||
{
|
||||
return $this->inEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the out edges.
|
||||
*
|
||||
* @return ServiceReferenceGraphEdge[]
|
||||
*/
|
||||
public function getOutEdges(): array
|
||||
{
|
||||
return $this->outEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this Node.
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all edges.
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->inEdges = $this->outEdges = [];
|
||||
}
|
||||
}
|
||||
137
backend/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php
vendored
Normal file
137
backend/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Definition\BaseNode;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
/**
|
||||
* Validates environment variable placeholders used in extension configuration with dummy values.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ValidateEnvPlaceholdersPass implements CompilerPassInterface
|
||||
{
|
||||
private const TYPE_FIXTURES = ['array' => [], 'bool' => false, 'float' => 0.0, 'int' => 0, 'string' => ''];
|
||||
|
||||
private array $extensionConfig = [];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$this->extensionConfig = [];
|
||||
|
||||
if (!class_exists(BaseNode::class) || !$extensions = $container->getExtensions()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resolvingBag = $container->getParameterBag();
|
||||
if (!$resolvingBag instanceof EnvPlaceholderParameterBag) {
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultBag = new ParameterBag($resolvingBag->all());
|
||||
$envTypes = $resolvingBag->getProvidedTypes();
|
||||
foreach ($resolvingBag->getEnvPlaceholders() + $resolvingBag->getUnusedEnvPlaceholders() as $env => $placeholders) {
|
||||
$values = $this->getPlaceholderValues($env, $defaultBag, $envTypes);
|
||||
|
||||
foreach ($placeholders as $placeholder) {
|
||||
BaseNode::setPlaceholder($placeholder, $values);
|
||||
}
|
||||
}
|
||||
|
||||
$processor = new Processor();
|
||||
|
||||
foreach ($extensions as $name => $extension) {
|
||||
if (!($extension instanceof ConfigurationExtensionInterface || $extension instanceof ConfigurationInterface)
|
||||
|| !$config = array_filter($container->getExtensionConfig($name))
|
||||
) {
|
||||
// this extension has no semantic configuration or was not called
|
||||
continue;
|
||||
}
|
||||
|
||||
$config = $resolvingBag->resolveValue($config);
|
||||
|
||||
if ($extension instanceof ConfigurationInterface) {
|
||||
$configuration = $extension;
|
||||
} elseif (null === $configuration = $extension->getConfiguration($config, $container)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->extensionConfig[$name] = $processor->processConfiguration($configuration, $config);
|
||||
}
|
||||
|
||||
$resolvingBag->clearUnusedEnvPlaceholders();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getExtensionConfig(): array
|
||||
{
|
||||
try {
|
||||
return $this->extensionConfig;
|
||||
} finally {
|
||||
$this->extensionConfig = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, list<string>> $envTypes
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function getPlaceholderValues(string $env, ParameterBag $defaultBag, array $envTypes): array
|
||||
{
|
||||
if (false === $i = strpos($env, ':')) {
|
||||
[$default, $defaultType] = $this->getParameterDefaultAndDefaultType("env($env)", $defaultBag);
|
||||
|
||||
return [$defaultType => $default];
|
||||
}
|
||||
|
||||
$prefix = substr($env, 0, $i);
|
||||
if ('default' === $prefix) {
|
||||
$parts = explode(':', $env);
|
||||
array_shift($parts); // Remove 'default' prefix
|
||||
$parameter = array_shift($parts); // Retrieve and remove parameter
|
||||
|
||||
[$defaultParameter, $defaultParameterType] = $this->getParameterDefaultAndDefaultType($parameter, $defaultBag);
|
||||
|
||||
return [
|
||||
$defaultParameterType => $defaultParameter,
|
||||
...$this->getPlaceholderValues(implode(':', $parts), $defaultBag, $envTypes),
|
||||
];
|
||||
}
|
||||
|
||||
$values = [];
|
||||
foreach ($envTypes[$prefix] ?? ['string'] as $type) {
|
||||
$values[$type] = self::TYPE_FIXTURES[$type] ?? null;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: string, 1: string}
|
||||
*/
|
||||
private function getParameterDefaultAndDefaultType(string $name, ParameterBag $defaultBag): array
|
||||
{
|
||||
$default = $defaultBag->has($name) ? $defaultBag->get($name) : self::TYPE_FIXTURES['string'];
|
||||
$defaultType = null !== $default ? get_debug_type($default) : 'string';
|
||||
|
||||
return [$default, $defaultType];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user