first commit
This commit is contained in:
108
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Alias.php
vendored
Normal file
108
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Alias.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
class Alias
|
||||
{
|
||||
private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%alias_id%" service alias is deprecated. You should stop using it, as it will be removed in the future.';
|
||||
|
||||
private string $id;
|
||||
private bool $public;
|
||||
private array $deprecation = [];
|
||||
|
||||
public function __construct(string $id, bool $public = false)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->public = $public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this DI Alias should be public or not.
|
||||
*/
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this Alias is public.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPublic(bool $boolean): static
|
||||
{
|
||||
$this->public = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this alias is private.
|
||||
*/
|
||||
public function isPrivate(): bool
|
||||
{
|
||||
return !$this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this alias is deprecated, that means it should not be referenced
|
||||
* anymore.
|
||||
*
|
||||
* @param string $package The name of the composer package that is triggering the deprecation
|
||||
* @param string $version The version of the package that introduced the deprecation
|
||||
* @param string $message The deprecation message to use
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException when the message template is invalid
|
||||
*/
|
||||
public function setDeprecated(string $package, string $version, string $message): static
|
||||
{
|
||||
if ('' !== $message) {
|
||||
if (preg_match('#[\r\n]|\*/#', $message)) {
|
||||
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
|
||||
}
|
||||
|
||||
if (!str_contains($message, '%alias_id%')) {
|
||||
throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->deprecation = ['package' => $package, 'version' => $version, 'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isDeprecated(): bool
|
||||
{
|
||||
return (bool) $this->deprecation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id Service id relying on this definition
|
||||
*/
|
||||
public function getDeprecation(string $id): array
|
||||
{
|
||||
return [
|
||||
'package' => $this->deprecation['package'],
|
||||
'version' => $this->deprecation['version'],
|
||||
'message' => str_replace('%alias_id%', $id, $this->deprecation['message']),
|
||||
];
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/AbstractArgument.php
vendored
Normal file
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/AbstractArgument.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?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\Argument;
|
||||
|
||||
/**
|
||||
* Represents an abstract service argument, which have to be set by a compiler pass or a DI extension.
|
||||
*/
|
||||
final class AbstractArgument
|
||||
{
|
||||
private string $text;
|
||||
private string $context = '';
|
||||
|
||||
public function __construct(string $text = '')
|
||||
{
|
||||
$this->text = trim($text, '. ');
|
||||
}
|
||||
|
||||
public function setContext(string $context): void
|
||||
{
|
||||
$this->context = $context.' is abstract'.('' === $this->text ? '' : ': ');
|
||||
}
|
||||
|
||||
public function getText(): string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
public function getTextWithContext(): string
|
||||
{
|
||||
return $this->context.$this->text.'.';
|
||||
}
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ArgumentInterface.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ArgumentInterface.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Argument;
|
||||
|
||||
/**
|
||||
* Represents a complex argument containing nested values.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
interface ArgumentInterface
|
||||
{
|
||||
public function getValues(): array;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setValues(array $values);
|
||||
}
|
56
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/BoundArgument.php
vendored
Normal file
56
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/BoundArgument.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\Argument;
|
||||
|
||||
/**
|
||||
* @author Guilhem Niot <guilhem.niot@gmail.com>
|
||||
*/
|
||||
final class BoundArgument implements ArgumentInterface
|
||||
{
|
||||
public const SERVICE_BINDING = 0;
|
||||
public const DEFAULTS_BINDING = 1;
|
||||
public const INSTANCEOF_BINDING = 2;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
private mixed $value;
|
||||
private ?int $identifier = null;
|
||||
private ?bool $used = null;
|
||||
private int $type;
|
||||
private ?string $file;
|
||||
|
||||
public function __construct(mixed $value, bool $trackUsage = true, int $type = 0, ?string $file = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
if ($trackUsage) {
|
||||
$this->identifier = ++self::$sequence;
|
||||
} else {
|
||||
$this->used = true;
|
||||
}
|
||||
$this->type = $type;
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public function getValues(): array
|
||||
{
|
||||
return [$this->value, $this->identifier, $this->used, $this->type, $this->file];
|
||||
}
|
||||
|
||||
public function setValues(array $values): void
|
||||
{
|
||||
if (5 === \count($values)) {
|
||||
[$this->value, $this->identifier, $this->used, $this->type, $this->file] = $values;
|
||||
} else {
|
||||
[$this->value, $this->identifier, $this->used] = $values;
|
||||
}
|
||||
}
|
||||
}
|
40
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/IteratorArgument.php
vendored
Normal file
40
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/IteratorArgument.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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\Argument;
|
||||
|
||||
/**
|
||||
* Represents a collection of values to lazily iterate over.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class IteratorArgument implements ArgumentInterface
|
||||
{
|
||||
private array $values;
|
||||
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->setValues($values);
|
||||
}
|
||||
|
||||
public function getValues(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setValues(array $values)
|
||||
{
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
96
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/LazyClosure.php
vendored
Normal file
96
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/LazyClosure.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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\Argument;
|
||||
|
||||
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\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LazyClosure
|
||||
{
|
||||
public readonly object $service;
|
||||
|
||||
public function __construct(
|
||||
private \Closure $initializer,
|
||||
) {
|
||||
unset($this->service);
|
||||
}
|
||||
|
||||
public function __get(mixed $name): mixed
|
||||
{
|
||||
if ('service' !== $name) {
|
||||
throw new InvalidArgumentException(sprintf('Cannot read property "%s" from a lazy closure.', $name));
|
||||
}
|
||||
|
||||
if (isset($this->initializer)) {
|
||||
$this->service = ($this->initializer)();
|
||||
unset($this->initializer);
|
||||
}
|
||||
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
public static function getCode(string $initializer, array $callable, Definition $definition, ContainerBuilder $container, ?string $id): string
|
||||
{
|
||||
$method = $callable[1];
|
||||
$asClosure = 'Closure' === ($definition->getClass() ?: 'Closure');
|
||||
|
||||
if ($asClosure) {
|
||||
$class = ($callable[0] instanceof Reference ? $container->findDefinition($callable[0]) : $callable[0])->getClass();
|
||||
} else {
|
||||
$class = $definition->getClass();
|
||||
}
|
||||
|
||||
$r = $container->getReflectionClass($class);
|
||||
|
||||
if (null !== $id) {
|
||||
$id = sprintf(' for service "%s"', $id);
|
||||
}
|
||||
|
||||
if (!$asClosure) {
|
||||
$id = str_replace('%', '%%', (string) $id);
|
||||
|
||||
if (!$r || !$r->isInterface()) {
|
||||
throw new RuntimeException(sprintf("Cannot create adapter{$id} because \"%s\" is not an interface.", $class));
|
||||
}
|
||||
if (1 !== \count($method = $r->getMethods())) {
|
||||
throw new RuntimeException(sprintf("Cannot create adapter{$id} because interface \"%s\" doesn't have exactly one method.", $class));
|
||||
}
|
||||
$method = $method[0]->name;
|
||||
} elseif (!$r || !$r->hasMethod($method)) {
|
||||
throw new RuntimeException("Cannot create lazy closure{$id} because its corresponding callable is invalid.");
|
||||
}
|
||||
|
||||
$methodReflector = $r->getMethod($method);
|
||||
$code = ProxyHelper::exportSignature($methodReflector, true, $args);
|
||||
|
||||
if ($asClosure) {
|
||||
$code = ' { '.preg_replace('/: static$/', ': \\'.$r->name, $code);
|
||||
} else {
|
||||
$code = ' implements \\'.$r->name.' { '.$code;
|
||||
}
|
||||
|
||||
$code = 'new class('.$initializer.') extends \\'.self::class
|
||||
.$code.' { '.($methodReflector->hasReturnType() && 'void' === (string) $methodReflector->getReturnType() ? '' : 'return ').'$this->service->'.$callable[1].'('.$args.'); } '
|
||||
.'}';
|
||||
|
||||
return $asClosure ? '('.$code.')->'.$method.'(...)' : $code;
|
||||
}
|
||||
}
|
@@ -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\Argument;
|
||||
|
||||
trigger_deprecation('symfony/dependency-injection', '6.1', '"%s" is deprecated.', ReferenceSetArgumentTrait::class);
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @deprecated since Symfony 6.1
|
||||
*/
|
||||
trait ReferenceSetArgumentTrait
|
||||
{
|
||||
private array $values;
|
||||
|
||||
/**
|
||||
* @param Reference[] $values
|
||||
*/
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->setValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Reference[]
|
||||
*/
|
||||
public function getValues(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reference[] $values The service references to put in the set
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setValues(array $values)
|
||||
{
|
||||
foreach ($values as $k => $v) {
|
||||
if (null !== $v && !$v instanceof Reference) {
|
||||
throw new InvalidArgumentException(sprintf('A "%s" must hold only Reference instances, "%s" given.', __CLASS__, get_debug_type($v)));
|
||||
}
|
||||
}
|
||||
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
43
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php
vendored
Normal file
43
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\Argument;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class RewindableGenerator implements \IteratorAggregate, \Countable
|
||||
{
|
||||
private \Closure $generator;
|
||||
private \Closure|int $count;
|
||||
|
||||
public function __construct(callable $generator, int|callable $count)
|
||||
{
|
||||
$this->generator = $generator(...);
|
||||
$this->count = \is_int($count) ? $count : $count(...);
|
||||
}
|
||||
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
$g = $this->generator;
|
||||
|
||||
return $g();
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
if (!\is_int($count = $this->count)) {
|
||||
$this->count = $count();
|
||||
}
|
||||
|
||||
return $this->count;
|
||||
}
|
||||
}
|
46
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceClosureArgument.php
vendored
Normal file
46
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceClosureArgument.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\Argument;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Represents a service wrapped in a memoizing closure.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ServiceClosureArgument implements ArgumentInterface
|
||||
{
|
||||
private array $values;
|
||||
|
||||
public function __construct(mixed $value)
|
||||
{
|
||||
$this->values = [$value];
|
||||
}
|
||||
|
||||
public function getValues(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setValues(array $values)
|
||||
{
|
||||
if ([0] !== array_keys($values)) {
|
||||
throw new InvalidArgumentException('A ServiceClosureArgument must hold one and only one value.');
|
||||
}
|
||||
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
48
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceLocator.php
vendored
Normal file
48
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceLocator.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?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\Argument;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ServiceLocator extends BaseServiceLocator
|
||||
{
|
||||
private \Closure $factory;
|
||||
private array $serviceMap;
|
||||
private ?array $serviceTypes;
|
||||
|
||||
public function __construct(\Closure $factory, array $serviceMap, ?array $serviceTypes = null)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->serviceMap = $serviceMap;
|
||||
$this->serviceTypes = $serviceTypes;
|
||||
parent::__construct($serviceMap);
|
||||
}
|
||||
|
||||
public function get(string $id): mixed
|
||||
{
|
||||
return match (\count($this->serviceMap[$id] ?? [])) {
|
||||
0 => parent::get($id),
|
||||
1 => $this->serviceMap[$id][0],
|
||||
default => ($this->factory)(...$this->serviceMap[$id]),
|
||||
};
|
||||
}
|
||||
|
||||
public function getProvidedServices(): array
|
||||
{
|
||||
return $this->serviceTypes ??= array_map(fn () => '?', $this->serviceMap);
|
||||
}
|
||||
}
|
51
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceLocatorArgument.php
vendored
Normal file
51
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/ServiceLocatorArgument.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\Argument;
|
||||
|
||||
/**
|
||||
* Represents a closure acting as a service locator.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ServiceLocatorArgument implements ArgumentInterface
|
||||
{
|
||||
private array $values;
|
||||
private ?TaggedIteratorArgument $taggedIteratorArgument = null;
|
||||
|
||||
public function __construct(array|TaggedIteratorArgument $values = [])
|
||||
{
|
||||
if ($values instanceof TaggedIteratorArgument) {
|
||||
$this->taggedIteratorArgument = $values;
|
||||
$values = [];
|
||||
}
|
||||
|
||||
$this->setValues($values);
|
||||
}
|
||||
|
||||
public function getTaggedIteratorArgument(): ?TaggedIteratorArgument
|
||||
{
|
||||
return $this->taggedIteratorArgument;
|
||||
}
|
||||
|
||||
public function getValues(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setValues(array $values)
|
||||
{
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
92
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php
vendored
Normal file
92
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?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\Argument;
|
||||
|
||||
/**
|
||||
* Represents a collection of services found by tag name to lazily iterate over.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class TaggedIteratorArgument extends IteratorArgument
|
||||
{
|
||||
private string $tag;
|
||||
private mixed $indexAttribute;
|
||||
private ?string $defaultIndexMethod;
|
||||
private ?string $defaultPriorityMethod;
|
||||
private bool $needsIndexes;
|
||||
private array $exclude;
|
||||
private bool $excludeSelf = true;
|
||||
|
||||
/**
|
||||
* @param string $tag The name of the tag identifying the target services
|
||||
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
|
||||
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
|
||||
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
|
||||
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
|
||||
* @param array $exclude Services to exclude from the iterator
|
||||
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
|
||||
*/
|
||||
public function __construct(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, bool $needsIndexes = false, ?string $defaultPriorityMethod = null, array $exclude = [], bool $excludeSelf = true)
|
||||
{
|
||||
parent::__construct([]);
|
||||
|
||||
if (null === $indexAttribute && $needsIndexes) {
|
||||
$indexAttribute = preg_match('/[^.]++$/', $tag, $m) ? $m[0] : $tag;
|
||||
}
|
||||
|
||||
$this->tag = $tag;
|
||||
$this->indexAttribute = $indexAttribute;
|
||||
$this->defaultIndexMethod = $defaultIndexMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name' : null);
|
||||
$this->needsIndexes = $needsIndexes;
|
||||
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Priority' : null);
|
||||
$this->exclude = $exclude;
|
||||
$this->excludeSelf = $excludeSelf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
public function getIndexAttribute(): ?string
|
||||
{
|
||||
return $this->indexAttribute;
|
||||
}
|
||||
|
||||
public function getDefaultIndexMethod(): ?string
|
||||
{
|
||||
return $this->defaultIndexMethod;
|
||||
}
|
||||
|
||||
public function needsIndexes(): bool
|
||||
{
|
||||
return $this->needsIndexes;
|
||||
}
|
||||
|
||||
public function getDefaultPriorityMethod(): ?string
|
||||
{
|
||||
return $this->defaultPriorityMethod;
|
||||
}
|
||||
|
||||
public function getExclude(): array
|
||||
{
|
||||
return $this->exclude;
|
||||
}
|
||||
|
||||
public function excludeSelf(): bool
|
||||
{
|
||||
return $this->excludeSelf;
|
||||
}
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsAlias.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsAlias.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell under which alias a service should be registered or to use the implemented interface if no parameter is given.
|
||||
*
|
||||
* @author Alan Poulain <contact@alanpoulain.eu>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
final class AsAlias
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $id = null,
|
||||
public bool $public = false,
|
||||
) {
|
||||
}
|
||||
}
|
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsDecorator.php
vendored
Normal file
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsDecorator.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class AsDecorator
|
||||
{
|
||||
public function __construct(
|
||||
public string $decorates,
|
||||
public int $priority = 0,
|
||||
public int $onInvalid = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,
|
||||
) {
|
||||
}
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsTaggedItem.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AsTaggedItem.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell under which index and priority a service class should be found in tagged iterators/locators.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class AsTaggedItem
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $index = null,
|
||||
public ?int $priority = null,
|
||||
) {
|
||||
}
|
||||
}
|
35
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Autoconfigure.php
vendored
Normal file
35
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Autoconfigure.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell how a base type should be autoconfigured.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
class Autoconfigure
|
||||
{
|
||||
public function __construct(
|
||||
public ?array $tags = null,
|
||||
public ?array $calls = null,
|
||||
public ?array $bind = null,
|
||||
public bool|string|null $lazy = null,
|
||||
public ?bool $public = null,
|
||||
public ?bool $shared = null,
|
||||
public ?bool $autowire = null,
|
||||
public ?array $properties = null,
|
||||
public array|string|null $configurator = null,
|
||||
public ?string $constructor = null,
|
||||
) {
|
||||
}
|
||||
}
|
30
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutoconfigureTag.php
vendored
Normal file
30
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutoconfigureTag.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell how a base type should be tagged.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
class AutoconfigureTag extends Autoconfigure
|
||||
{
|
||||
public function __construct(?string $name = null, array $attributes = [])
|
||||
{
|
||||
parent::__construct(
|
||||
tags: [
|
||||
[$name ?? 0 => $attributes],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
75
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Autowire.php
vendored
Normal file
75
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Autowire.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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
/**
|
||||
* Attribute to tell a parameter how to be autowired.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class Autowire
|
||||
{
|
||||
public readonly string|array|Expression|Reference|ArgumentInterface|null $value;
|
||||
public readonly bool|array $lazy;
|
||||
|
||||
/**
|
||||
* Use only ONE of the following.
|
||||
*
|
||||
* @param string|array|ArgumentInterface|null $value Value to inject (ie "%kernel.project_dir%/some/path")
|
||||
* @param string|null $service Service ID (ie "some.service")
|
||||
* @param string|null $expression Expression (ie 'service("some.service").someMethod()')
|
||||
* @param string|null $env Environment variable name (ie 'SOME_ENV_VARIABLE')
|
||||
* @param string|null $param Parameter name (ie 'some.parameter.name')
|
||||
* @param bool|class-string|class-string[] $lazy Whether to use lazy-loading for this argument
|
||||
*/
|
||||
public function __construct(
|
||||
string|array|ArgumentInterface|null $value = null,
|
||||
?string $service = null,
|
||||
?string $expression = null,
|
||||
?string $env = null,
|
||||
?string $param = null,
|
||||
bool|string|array $lazy = false,
|
||||
) {
|
||||
if ($this->lazy = \is_string($lazy) ? [$lazy] : $lazy) {
|
||||
if (null !== ($expression ?? $env ?? $param)) {
|
||||
throw new LogicException('#[Autowire] attribute cannot be $lazy and use $expression, $env, or $param.');
|
||||
}
|
||||
if (null !== $value && null !== $service) {
|
||||
throw new LogicException('#[Autowire] attribute cannot declare $value and $service at the same time.');
|
||||
}
|
||||
} elseif (!(null !== $value xor null !== $service xor null !== $expression xor null !== $env xor null !== $param)) {
|
||||
throw new LogicException('#[Autowire] attribute must declare exactly one of $service, $expression, $env, $param or $value.');
|
||||
}
|
||||
|
||||
if (\is_string($value) && str_starts_with($value, '@')) {
|
||||
match (true) {
|
||||
str_starts_with($value, '@@') => $value = substr($value, 1),
|
||||
str_starts_with($value, '@=') => $expression = substr($value, 2),
|
||||
default => $service = substr($value, 1),
|
||||
};
|
||||
}
|
||||
|
||||
$this->value = match (true) {
|
||||
null !== $service => new Reference($service),
|
||||
null !== $expression => class_exists(Expression::class) ? new Expression($expression) : throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".'),
|
||||
null !== $env => "%env($env)%",
|
||||
null !== $param => "%$param%",
|
||||
default => $value,
|
||||
};
|
||||
}
|
||||
}
|
50
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireCallable.php
vendored
Normal file
50
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireCallable.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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Attribute to tell which callable to give to an argument of type Closure.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class AutowireCallable extends Autowire
|
||||
{
|
||||
/**
|
||||
* @param bool|class-string $lazy Whether to use lazy-loading for this argument
|
||||
*/
|
||||
public function __construct(
|
||||
string|array|null $callable = null,
|
||||
?string $service = null,
|
||||
?string $method = null,
|
||||
bool|string $lazy = false,
|
||||
) {
|
||||
if (!(null !== $callable xor null !== $service)) {
|
||||
throw new LogicException('#[AutowireCallable] attribute must declare exactly one of $callable or $service.');
|
||||
}
|
||||
if (null === $service && null !== $method) {
|
||||
throw new LogicException('#[AutowireCallable] attribute cannot have a $method without a $service.');
|
||||
}
|
||||
|
||||
parent::__construct($callable ?? [new Reference($service), $method ?? '__invoke'], lazy: $lazy);
|
||||
}
|
||||
|
||||
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
|
||||
{
|
||||
return (new Definition($type = \is_array($this->lazy) ? current($this->lazy) : ($type ?: 'Closure')))
|
||||
->setFactory(['Closure', 'fromCallable'])
|
||||
->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value])
|
||||
->setLazy($this->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType());
|
||||
}
|
||||
}
|
17
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireDecorated.php
vendored
Normal file
17
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireDecorated.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?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\Attribute;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class AutowireDecorated
|
||||
{
|
||||
}
|
35
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireIterator.php
vendored
Normal file
35
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireIterator.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
|
||||
/**
|
||||
* Autowires an iterator of services based on a tag name.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class AutowireIterator extends Autowire
|
||||
{
|
||||
/**
|
||||
* @param string|string[] $exclude A service or a list of services to exclude
|
||||
*/
|
||||
public function __construct(
|
||||
string $tag,
|
||||
?string $indexAttribute = null,
|
||||
?string $defaultIndexMethod = null,
|
||||
?string $defaultPriorityMethod = null,
|
||||
string|array $exclude = [],
|
||||
bool $excludeSelf = true,
|
||||
) {
|
||||
parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
|
||||
}
|
||||
}
|
82
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireLocator.php
vendored
Normal file
82
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireLocator.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Contracts\Service\Attribute\SubscribedService;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Autowires a service locator based on a tag name or an explicit list of key => service-type pairs.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class AutowireLocator extends Autowire
|
||||
{
|
||||
/**
|
||||
* @see ServiceSubscriberInterface::getSubscribedServices()
|
||||
*
|
||||
* @param string|array<string|Autowire|SubscribedService> $services An explicit list of services or a tag name
|
||||
* @param string|string[] $exclude A service or a list of services to exclude
|
||||
*/
|
||||
public function __construct(
|
||||
string|array $services,
|
||||
?string $indexAttribute = null,
|
||||
?string $defaultIndexMethod = null,
|
||||
?string $defaultPriorityMethod = null,
|
||||
string|array $exclude = [],
|
||||
bool $excludeSelf = true,
|
||||
) {
|
||||
if (\is_string($services)) {
|
||||
parent::__construct(new ServiceLocatorArgument(new TaggedIteratorArgument($services, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$references = [];
|
||||
|
||||
foreach ($services as $key => $type) {
|
||||
$attributes = [];
|
||||
|
||||
if ($type instanceof Autowire) {
|
||||
$references[$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" is used, a type must be set.', 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" is not a PHP type for key "%s".', \is_string($type) ? $type : get_debug_type($type), $key));
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
$references[$key] = new TypedReference($type, $type, $optionalBehavior, $name, $attributes);
|
||||
}
|
||||
|
||||
parent::__construct(new ServiceLocatorArgument($references));
|
||||
}
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireServiceClosure.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/AutowireServiceClosure.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Attribute to wrap a service in a closure that returns it.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class AutowireServiceClosure extends Autowire
|
||||
{
|
||||
public function __construct(string $service)
|
||||
{
|
||||
parent::__construct(new ServiceClosureArgument(new Reference($service)));
|
||||
}
|
||||
}
|
22
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Exclude.php
vendored
Normal file
22
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Exclude.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell the class should not be registered as service.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Exclude
|
||||
{
|
||||
}
|
22
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/MapDecorated.php
vendored
Normal file
22
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/MapDecorated.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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\Attribute;
|
||||
|
||||
trigger_deprecation('symfony/dependency-injection', '6.3', 'The "%s" class is deprecated, use "%s" instead.', MapDecorated::class, AutowireDecorated::class);
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.3, use AutowireDecorated instead
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class MapDecorated
|
||||
{
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/TaggedIterator.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/TaggedIterator.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Attribute;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class TaggedIterator extends AutowireIterator
|
||||
{
|
||||
public function __construct(
|
||||
public string $tag,
|
||||
public ?string $indexAttribute = null,
|
||||
public ?string $defaultIndexMethod = null,
|
||||
public ?string $defaultPriorityMethod = null,
|
||||
public string|array $exclude = [],
|
||||
public bool $excludeSelf = true,
|
||||
) {
|
||||
parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf);
|
||||
}
|
||||
}
|
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/TaggedLocator.php
vendored
Normal file
27
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/TaggedLocator.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Attribute;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class TaggedLocator extends AutowireLocator
|
||||
{
|
||||
public function __construct(
|
||||
public string $tag,
|
||||
public ?string $indexAttribute = null,
|
||||
public ?string $defaultIndexMethod = null,
|
||||
public ?string $defaultPriorityMethod = null,
|
||||
public string|array $exclude = [],
|
||||
public bool $excludeSelf = true,
|
||||
) {
|
||||
parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf);
|
||||
}
|
||||
}
|
64
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Target.php
vendored
Normal file
64
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/Target.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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\Attribute;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* An attribute to tell how a dependency is used and hint named autowiring aliases.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
final class Target
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $name = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getParsedName(): string
|
||||
{
|
||||
if (null === $this->name) {
|
||||
throw new LogicException(sprintf('Cannot parse the name of a #[Target] attribute that has not been resolved. Did you forget to call "%s::parseName()"?', __CLASS__));
|
||||
}
|
||||
|
||||
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->name))));
|
||||
}
|
||||
|
||||
public static function parseName(\ReflectionParameter $parameter, ?self &$attribute = null, ?string &$parsedName = null): string
|
||||
{
|
||||
$attribute = null;
|
||||
if (!$target = $parameter->getAttributes(self::class)[0] ?? null) {
|
||||
$parsedName = (new self($parameter->name))->getParsedName();
|
||||
|
||||
return $parameter->name;
|
||||
}
|
||||
|
||||
$attribute = $target->newInstance();
|
||||
$name = $attribute->name ??= $parameter->name;
|
||||
$parsedName = $attribute->getParsedName();
|
||||
|
||||
if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $parsedName)) {
|
||||
if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) {
|
||||
$function = $function->class.'::'.$function->name;
|
||||
} else {
|
||||
$function = $function->name;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Invalid #[Target] name "%s" on parameter "$%s" of "%s()": the first character must be a letter.', $name, $parameter->name, $function));
|
||||
}
|
||||
|
||||
return preg_match('/^[a-zA-Z0-9_\x7f-\xff]++$/', $name) ? $name : $parsedName;
|
||||
}
|
||||
}
|
26
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/When.php
vendored
Normal file
26
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Attribute/When.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell under which environment this class should be registered as a service.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
|
||||
class When
|
||||
{
|
||||
public function __construct(
|
||||
public string $env,
|
||||
) {
|
||||
}
|
||||
}
|
371
plugins/simplesaml/lib/vendor/symfony/dependency-injection/CHANGELOG.md
vendored
Normal file
371
plugins/simplesaml/lib/vendor/symfony/dependency-injection/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.4
|
||||
---
|
||||
|
||||
* Allow using `#[Target]` with no arguments to state that a parameter must match a named autowiring alias
|
||||
* Deprecate `ContainerAwareInterface` and `ContainerAwareTrait`, use dependency injection instead
|
||||
* Add `defined` env var processor that returns `true` for defined and neither null nor empty env vars
|
||||
* Add `#[AutowireLocator]` and `#[AutowireIterator]` attributes
|
||||
|
||||
6.3
|
||||
---
|
||||
|
||||
* Add options `inline_factories` and `inline_class_loader` to `PhpDumper::dump()`
|
||||
* Deprecate `PhpDumper` options `inline_factories_parameter` and `inline_class_loader_parameter`
|
||||
* Add `RemoveBuildParametersPass`, which removes parameters starting with a dot during compilation
|
||||
* Add support for nesting autowiring-related attributes into `#[Autowire(...)]`
|
||||
* Deprecate undefined and numeric keys with `service_locator` config
|
||||
* Fail if Target attribute does not exist during compilation
|
||||
* Enable deprecating parameters with `ContainerBuilder::deprecateParameter()`
|
||||
* Add `#[AsAlias]` attribute to tell under which alias a service should be registered or to use the implemented interface if no parameter is given
|
||||
* Allow to trim XML service parameters value by using `trim="true"` attribute
|
||||
* Allow extending the `Autowire` attribute
|
||||
* Add `#[Exclude]` to skip autoregistering a class
|
||||
* Add support for generating lazy closures
|
||||
* Add support for autowiring services as closures using `#[AutowireCallable]` or `#[AutowireServiceClosure]`
|
||||
* Add support for `#[Autowire(lazy: true|class-string)]`
|
||||
* Make it possible to cast callables into single-method interfaces
|
||||
* Deprecate `#[MapDecorated]`, use `#[AutowireDecorated]` instead
|
||||
* Deprecate the `@required` annotation, use the `Symfony\Contracts\Service\Attribute\Required` attribute instead
|
||||
* Add `constructor` option to services declaration and to `#[Autoconfigure]`
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Use lazy-loading ghost objects and virtual proxies out of the box
|
||||
* Add arguments `&$asGhostObject` and `$id` to LazyProxy's `DumperInterface` to allow using ghost objects for lazy loading services
|
||||
* Add `enum` env var processor
|
||||
* Add `shuffle` env var processor
|
||||
* Allow #[When] to be extended
|
||||
* Change the signature of `ContainerAwareInterface::setContainer()` to `setContainer(?ContainerInterface)`
|
||||
* Deprecate calling `ContainerAwareTrait::setContainer()` without arguments
|
||||
* Deprecate using numeric parameter names
|
||||
* Add support for tagged iterators/locators `exclude` option to the xml and yaml loaders/dumpers
|
||||
* Allow injecting `string $env` into php config closures
|
||||
* Add `excludeSelf` parameter to `TaggedIteratorArgument` with default value to `true`
|
||||
to control whether the referencing service should be automatically excluded from the iterator
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* Add `#[MapDecorated]` attribute telling to which parameter the decorated service should be mapped in a decorator
|
||||
* Add `#[AsDecorator]` attribute to make a service decorates another
|
||||
* Add `$exclude` to `TaggedIterator` and `TaggedLocator` attributes
|
||||
* Add `$exclude` to `tagged_iterator` and `tagged_locator` configurator
|
||||
* Add an `env` function to the expression language provider
|
||||
* Add an `Autowire` attribute to tell a parameter how to be autowired
|
||||
* Allow using expressions as service factories
|
||||
* Add argument type `closure` to help passing closures to services
|
||||
* Deprecate `ReferenceSetArgumentTrait`
|
||||
* Add `AbstractExtension` class for DI configuration/definition on a single file
|
||||
|
||||
6.0
|
||||
---
|
||||
|
||||
* Remove `Definition::setPrivate()` and `Alias::setPrivate()`, use `setPublic()` instead
|
||||
* Remove `inline()` in favor of `inline_service()` and `ref()` in favor of `service()` when using the PHP-DSL
|
||||
* Remove `Definition::getDeprecationMessage()`, use `Definition::getDeprecation()` instead
|
||||
* Remove `Alias::getDeprecationMessage()`, use `Alias::getDeprecation()` instead
|
||||
* Remove the `Psr\Container\ContainerInterface` and `Symfony\Component\DependencyInjection\ContainerInterface` aliases of the `service_container` service
|
||||
|
||||
5.4
|
||||
---
|
||||
* Add `$defaultIndexMethod` and `$defaultPriorityMethod` to `TaggedIterator` and `TaggedLocator` attributes
|
||||
* Add `service_closure()` to the PHP-DSL
|
||||
* Add support for autoconfigurable attributes on methods, properties and parameters
|
||||
* Make auto-aliases private by default
|
||||
* Add support for autowiring union and intersection types
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* Add `ServicesConfigurator::remove()` in the PHP-DSL
|
||||
* Add `%env(not:...)%` processor to negate boolean values
|
||||
* Add support for loading autoconfiguration rules via the `#[Autoconfigure]` and `#[AutoconfigureTag]` attributes on PHP 8
|
||||
* Add `#[AsTaggedItem]` attribute for defining the index and priority of classes found in tagged iterators/locators
|
||||
* Add autoconfigurable attributes
|
||||
* Add support for autowiring tagged iterators and locators via attributes on PHP 8
|
||||
* Add support for per-env configuration in XML and Yaml loaders
|
||||
* Add `ContainerBuilder::willBeAvailable()` to help with conditional configuration
|
||||
* Add support an integer return value for default_index_method
|
||||
* Add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match
|
||||
* Add `env()` and `EnvConfigurator` in the PHP-DSL
|
||||
* Add support for `ConfigBuilder` in the `PhpFileLoader`
|
||||
* Add `ContainerConfigurator::env()` to get the current environment
|
||||
* Add `#[Target]` to tell how a dependency is used and hint named autowiring aliases
|
||||
|
||||
5.2.0
|
||||
-----
|
||||
|
||||
* added `param()` and `abstract_arg()` in the PHP-DSL
|
||||
* deprecated `Definition::setPrivate()` and `Alias::setPrivate()`, use `setPublic()` instead
|
||||
* added support for the `#[Required]` attribute
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* deprecated `inline()` in favor of `inline_service()` and `ref()` in favor of `service()` when using the PHP-DSL
|
||||
* allow decorators to reference their decorated service using the special `.inner` id
|
||||
* added support to autowire public typed properties in php 7.4
|
||||
* added support for defining method calls, a configurator, and property setters in `InlineServiceConfigurator`
|
||||
* added possibility to define abstract service arguments
|
||||
* allowed mixing "parent" and instanceof-conditionals/defaults/bindings
|
||||
* updated the signature of method `Definition::setDeprecated()` to `Definition::setDeprecation(string $package, string $version, string $message)`
|
||||
* updated the signature of method `Alias::setDeprecated()` to `Alias::setDeprecation(string $package, string $version, string $message)`
|
||||
* updated the signature of method `DeprecateTrait::deprecate()` to `DeprecateTrait::deprecation(string $package, string $version, string $message)`
|
||||
* deprecated the `Psr\Container\ContainerInterface` and `Symfony\Component\DependencyInjection\ContainerInterface` aliases of the `service_container` service,
|
||||
configure them explicitly instead
|
||||
* added class `Symfony\Component\DependencyInjection\Dumper\Preloader` to help with preloading on PHP 7.4+
|
||||
* added tags `container.preload`/`.no_preload` to declare extra classes to preload/services to not preload
|
||||
* allowed loading and dumping tags with an attribute named "name"
|
||||
* deprecated `Definition::getDeprecationMessage()`, use `Definition::getDeprecation()` instead
|
||||
* deprecated `Alias::getDeprecationMessage()`, use `Alias::getDeprecation()` instead
|
||||
* added support of PHP8 static return type for withers
|
||||
* added `AliasDeprecatedPublicServicesPass` to deprecate public services to private
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* removed support for auto-discovered extension configuration class which does not implement `ConfigurationInterface`
|
||||
* removed support for non-string default env() parameters
|
||||
* moved `ServiceSubscriberInterface` to the `Symfony\Contracts\Service` namespace
|
||||
* removed `RepeatedPass` and `RepeatablePassInterface`
|
||||
* removed support for short factory/configurator syntax from `YamlFileLoader`
|
||||
* removed `ResettableContainerInterface`, use `ResetInterface` instead
|
||||
* added argument `$returnsClone` to `Definition::addMethodCall()`
|
||||
* removed `tagged`, use `tagged_iterator` instead
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* added `CheckTypeDeclarationsPass` to check injected parameters type during compilation
|
||||
* added support for opcache.preload by generating a preloading script in the cache folder
|
||||
* added support for dumping the container in one file instead of many files
|
||||
* deprecated support for short factories and short configurators in Yaml
|
||||
* added `tagged_iterator` alias for `tagged` which might be deprecated in a future version
|
||||
* deprecated passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition`
|
||||
* added support for binding iterable and tagged services
|
||||
* made singly-implemented interfaces detection be scoped by file
|
||||
* added ability to define a static priority method for tagged service
|
||||
* added support for improved syntax to define method calls in Yaml
|
||||
* made the `%env(base64:...)%` processor able to decode base64url
|
||||
* added ability to choose behavior of decorations on non existent decorated services
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* added `%env(trim:...)%` processor to trim a string value
|
||||
* added `%env(default:param_name:...)%` processor to fallback to a parameter or to null when using `%env(default::...)%`
|
||||
* added `%env(url:...)%` processor to convert a URL or DNS into an array of components
|
||||
* added `%env(query_string:...)%` processor to convert a query string into an array of key values
|
||||
* added support for deprecating aliases
|
||||
* made `ContainerParametersResource` final and not implement `Serializable` anymore
|
||||
* added `ReverseContainer`: a container that turns services back to their ids
|
||||
* added ability to define an index for a tagged collection
|
||||
* added ability to define an index for services in an injected service locator argument
|
||||
* made `ServiceLocator` implement `ServiceProviderInterface`
|
||||
* deprecated support for non-string default env() parameters
|
||||
* added `%env(require:...)%` processor to `require()` a PHP file and use the value returned from it
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* added `ContainerBuilder::registerAliasForArgument()` to support autowiring by type+name
|
||||
* added support for binding by type+name
|
||||
* added `ServiceSubscriberTrait` to ease implementing `ServiceSubscriberInterface` using methods' return types
|
||||
* added `ServiceLocatorArgument` and `!service_locator` config tag for creating optimized service-locators
|
||||
* added support for autoconfiguring bindings
|
||||
* added `%env(key:...)%` processor to fetch a specific key from an array
|
||||
* deprecated `ServiceSubscriberInterface`, use the same interface from the `Symfony\Contracts\Service` namespace instead
|
||||
* deprecated `ResettableContainerInterface`, use `Symfony\Contracts\Service\ResetInterface` instead
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* added support for variadics in named arguments
|
||||
* added PSR-11 `ContainerBagInterface` and its `ContainerBag` implementation to access parameters as-a-service
|
||||
* added support for service's decorators autowiring
|
||||
* deprecated the `TypedReference::canBeAutoregistered()` and `TypedReference::getRequiringClass()` methods
|
||||
* environment variables are validated when used in extension configuration
|
||||
* deprecated support for auto-discovered extension configuration class which does not implement `ConfigurationInterface`
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* Relying on service auto-registration while autowiring is not supported anymore.
|
||||
Explicitly inject your dependencies or create services whose ids are
|
||||
their fully-qualified class name.
|
||||
|
||||
Before:
|
||||
|
||||
```php
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Mailer;
|
||||
|
||||
class DefaultController
|
||||
{
|
||||
public function __construct(Mailer $mailer) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
```yml
|
||||
services:
|
||||
App\Controller\DefaultController:
|
||||
autowire: true
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```php
|
||||
// same PHP code
|
||||
```
|
||||
```yml
|
||||
services:
|
||||
App\Controller\DefaultController:
|
||||
autowire: true
|
||||
|
||||
# or
|
||||
# App\Controller\DefaultController:
|
||||
# arguments: { $mailer: "@App\Mailer" }
|
||||
|
||||
App\Mailer:
|
||||
autowire: true
|
||||
```
|
||||
* removed autowiring services based on the types they implement
|
||||
* added a third `$methodName` argument to the `getProxyFactoryCode()` method
|
||||
of the `DumperInterface`
|
||||
* removed support for autowiring types
|
||||
* removed `Container::isFrozen`
|
||||
* removed support for dumping an ucompiled container in `PhpDumper`
|
||||
* removed support for generating a dumped `Container` without populating the method map
|
||||
* removed support for case insensitive service identifiers
|
||||
* removed the `DefinitionDecorator` class, replaced by `ChildDefinition`
|
||||
* removed the `AutowireServiceResource` class and related `AutowirePass::createResourceForClass()` method
|
||||
* removed `LoggingFormatter`, `Compiler::getLoggingFormatter()` and `addLogMessage()` class and methods, use the `ContainerBuilder::log()` method instead
|
||||
* removed `FactoryReturnTypePass`
|
||||
* removed `ContainerBuilder::addClassResource()`, use the `addObjectResource()` or the `getReflectionClass()` method instead.
|
||||
* removed support for top-level anonymous services
|
||||
* removed silent behavior for unused attributes and elements
|
||||
* removed support for setting and accessing private services in `Container`
|
||||
* removed support for setting pre-defined services in `Container`
|
||||
* removed support for case insensitivity of parameter names
|
||||
* removed `AutowireExceptionPass` and `AutowirePass::getAutowiringExceptions()`, use `Definition::addError()` and the `DefinitionErrorExceptionPass` instead
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* moved the `ExtensionCompilerPass` to before-optimization passes with priority -1000
|
||||
* deprecated "public-by-default" definitions and aliases, the new default will be "private" in 4.0
|
||||
* added `EnvVarProcessorInterface` and corresponding "container.env_var_processor" tag for processing env vars
|
||||
* added support for ignore-on-uninitialized references
|
||||
* deprecated service auto-registration while autowiring
|
||||
* deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method
|
||||
* deprecated support for top-level anonymous services in XML
|
||||
* deprecated case insensitivity of parameter names
|
||||
* deprecated the `ResolveDefinitionTemplatesPass` class in favor of `ResolveChildDefinitionsPass`
|
||||
* added `TaggedIteratorArgument` with YAML (`!tagged foo`) and XML (`<service type="tagged"/>`) support
|
||||
* deprecated `AutowireExceptionPass` and `AutowirePass::getAutowiringExceptions()`, use `Definition::addError()` and the `DefinitionErrorExceptionPass` instead
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* deprecated autowiring services based on the types they implement;
|
||||
rename (or alias) your services to their FQCN id to make them autowirable
|
||||
* added "ServiceSubscriberInterface" - to allow for per-class explicit service-locator definitions
|
||||
* added "container.service_locator" tag for defining service-locator services
|
||||
* added anonymous services support in YAML configuration files using the `!service` tag.
|
||||
* added "TypedReference" and "ServiceClosureArgument" for creating service-locator services
|
||||
* added `ServiceLocator` - a PSR-11 container holding a set of services to be lazily loaded
|
||||
* added "instanceof" section for local interface-defined configs
|
||||
* added prototype services for PSR4-based discovery and registration
|
||||
* added `ContainerBuilder::getReflectionClass()` for retrieving and tracking reflection class info
|
||||
* deprecated `ContainerBuilder::getClassResource()`, use `ContainerBuilder::getReflectionClass()` or `ContainerBuilder::addObjectResource()` instead
|
||||
* added `ContainerBuilder::fileExists()` for checking and tracking file or directory existence
|
||||
* deprecated autowiring-types, use aliases instead
|
||||
* added support for omitting the factory class name in a service definition if the definition class is set
|
||||
* deprecated case insensitivity of service identifiers
|
||||
* added "iterator" argument type for lazy iteration over a set of values and services
|
||||
* added file-wide configurable defaults for service attributes "public", "tags",
|
||||
"autowire" and "autoconfigure"
|
||||
* made the "class" attribute optional, using the "id" as fallback
|
||||
* using the `PhpDumper` with an uncompiled `ContainerBuilder` is deprecated and
|
||||
will not be supported anymore in 4.0
|
||||
* deprecated the `DefinitionDecorator` class in favor of `ChildDefinition`
|
||||
* allow config files to be loaded using a glob pattern
|
||||
* [BC BREAK] the `NullDumper` class is now final
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* allowed to prioritize compiler passes by introducing a third argument to `PassConfig::addPass()`, to `Compiler::addPass` and to `ContainerBuilder::addCompilerPass()`
|
||||
* added support for PHP constants in YAML configuration files
|
||||
* deprecated the ability to set or unset a private service with the `Container::set()` method
|
||||
* deprecated the ability to check for the existence of a private service with the `Container::has()` method
|
||||
* deprecated the ability to request a private service with the `Container::get()` method
|
||||
* deprecated support for generating a dumped `Container` without populating the method map
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
* removed all deprecated codes from 2.x versions
|
||||
|
||||
2.8.0
|
||||
-----
|
||||
|
||||
* deprecated the abstract ContainerAware class in favor of ContainerAwareTrait
|
||||
* deprecated IntrospectableContainerInterface, to be merged with ContainerInterface in 3.0
|
||||
* allowed specifying a directory to recursively load all configuration files it contains
|
||||
* deprecated the concept of scopes
|
||||
* added `Definition::setShared()` and `Definition::isShared()`
|
||||
* added ResettableContainerInterface to be able to reset the container to release memory on shutdown
|
||||
* added a way to define the priority of service decoration
|
||||
* added support for service autowiring
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
* deprecated synchronized services
|
||||
|
||||
2.6.0
|
||||
-----
|
||||
|
||||
* added new factory syntax and deprecated the old one
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService())
|
||||
* deprecated SimpleXMLElement class.
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
||||
* added support for expressions in service definitions
|
||||
* added ContainerAwareTrait to add default container aware behavior to a class
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added Extension::isConfigEnabled() to ease working with enableable configurations
|
||||
* added an Extension base class with sensible defaults to be used in conjunction
|
||||
with the Config component.
|
||||
* added PrependExtensionInterface (to be able to allow extensions to prepend
|
||||
application configuration settings for any Bundle)
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added IntrospectableContainerInterface (to be able to check if a service
|
||||
has been initialized or not)
|
||||
* added ConfigurationExtensionInterface
|
||||
* added Definition::clearTag()
|
||||
* component exceptions that inherit base SPL classes are now used exclusively
|
||||
(this includes dumped containers)
|
||||
* [BC BREAK] fixed unescaping of class arguments, method
|
||||
ParameterBag::unescapeValue() was made public
|
95
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ChildDefinition.php
vendored
Normal file
95
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ChildDefinition.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* This definition extends another definition.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ChildDefinition extends Definition
|
||||
{
|
||||
private string $parent;
|
||||
|
||||
/**
|
||||
* @param string $parent The id of Definition instance to decorate
|
||||
*/
|
||||
public function __construct(string $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definition to inherit from.
|
||||
*/
|
||||
public function getParent(): string
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Definition to inherit from.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParent(string $parent): static
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* If replaceArgument() has been used to replace an argument, this method
|
||||
* will return the replacement value.
|
||||
*
|
||||
* @throws OutOfBoundsException When the argument does not exist
|
||||
*/
|
||||
public function getArgument(int|string $index): mixed
|
||||
{
|
||||
if (\array_key_exists('index_'.$index, $this->arguments)) {
|
||||
return $this->arguments['index_'.$index];
|
||||
}
|
||||
|
||||
return parent::getArgument($index);
|
||||
}
|
||||
|
||||
/**
|
||||
* You should always use this method when overwriting existing arguments
|
||||
* of the parent definition.
|
||||
*
|
||||
* If you directly call setArguments() keep in mind that you must follow
|
||||
* certain conventions when you want to overwrite the arguments of the
|
||||
* parent definition, otherwise your arguments will only be appended.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException when $index isn't an integer
|
||||
*/
|
||||
public function replaceArgument(int|string $index, mixed $value): static
|
||||
{
|
||||
if (\is_int($index)) {
|
||||
$this->arguments['index_'.$index] = $value;
|
||||
} elseif (str_starts_with($index, '$')) {
|
||||
$this->arguments[$index] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException('The argument must be an existing index or the name of a constructor\'s parameter.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
263
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php
vendored
Normal file
263
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @var ContainerBuilder
|
||||
*/
|
||||
protected $container;
|
||||
protected $currentId;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function enableExpressionProcessing()
|
||||
{
|
||||
$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.');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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->isPublic() || $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);
|
||||
}
|
||||
}
|
205
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php
vendored
Normal file
205
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
<?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 $onlyConstructorArguments;
|
||||
private bool $hasProxyDumper;
|
||||
private bool $lazy;
|
||||
private bool $byConstructor;
|
||||
private bool $byFactory;
|
||||
private array $definitions;
|
||||
private array $aliases;
|
||||
|
||||
/**
|
||||
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
|
||||
*/
|
||||
public function __construct(bool $onlyConstructorArguments = false, bool $hasProxyDumper = true)
|
||||
{
|
||||
$this->onlyConstructorArguments = $onlyConstructorArguments;
|
||||
$this->hasProxyDumper = $hasProxyDumper;
|
||||
$this->enableExpressionProcessing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a ContainerBuilder object to populate the service reference graph.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
$this->graph->clear();
|
||||
$this->lazy = false;
|
||||
$this->byConstructor = false;
|
||||
$this->byFactory = 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;
|
||||
parent::processValue($value->getValues());
|
||||
$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
|
||||
);
|
||||
|
||||
if ($inExpression) {
|
||||
$this->graph->connect(
|
||||
'.internal.reference_in_expression',
|
||||
null,
|
||||
$targetId,
|
||||
$targetDefinition,
|
||||
$value,
|
||||
$this->lazy || $targetDefinition?->isLazy(),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,170 @@
|
||||
<?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->getAutoconfiguredAttributes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container->getAutoconfiguredAttributes() as $attributeName => $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()));
|
||||
}
|
||||
|
||||
try {
|
||||
$attributeReflector = new \ReflectionClass($attributeName);
|
||||
} catch (\ReflectionException) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$targets = $attributeReflector->getAttributes(\Attribute::class)[0] ?? 0;
|
||||
$targets = $targets ? $targets->getArguments()[0] ?? -1 : 0;
|
||||
|
||||
foreach (['class', 'method', 'property', 'parameter'] as $symbol) {
|
||||
if (['Reflector'] !== $types) {
|
||||
if (!\in_array('Reflection'.ucfirst($symbol), $types, true)) {
|
||||
continue;
|
||||
}
|
||||
if (!($targets & \constant('Attribute::TARGET_'.strtoupper($symbol)))) {
|
||||
throw new LogicException(sprintf('Invalid type "Reflection%s" on argument "$%s": attribute "%s" cannot target a '.$symbol.' in "%s" on line "%d".', ucfirst($symbol), $reflectorParameter->getName(), $attributeName, $callableReflector->getFileName(), $callableReflector->getStartLine()));
|
||||
}
|
||||
}
|
||||
$this->{$symbol.'AttributeConfigurators'}[$attributeName] = $callable;
|
||||
}
|
||||
}
|
||||
|
||||
parent::process($container);
|
||||
}
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (!$value instanceof Definition
|
||||
|| !$value->isAutoconfigured()
|
||||
|| $value->isAbstract()
|
||||
|| $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('');
|
||||
|
||||
if ($this->classAttributeConfigurators) {
|
||||
foreach ($classReflector->getAttributes() as $attribute) {
|
||||
if ($configurator = $this->classAttributeConfigurators[$attribute->getName()] ?? null) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $classReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->parameterAttributeConfigurators) {
|
||||
try {
|
||||
$constructorReflector = $this->getConstructor($value, false);
|
||||
} catch (RuntimeException) {
|
||||
$constructorReflector = null;
|
||||
}
|
||||
|
||||
if ($constructorReflector) {
|
||||
foreach ($constructorReflector->getParameters() as $parameterReflector) {
|
||||
foreach ($parameterReflector->getAttributes() as $attribute) {
|
||||
if ($configurator = $this->parameterAttributeConfigurators[$attribute->getName()] ?? null) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $parameterReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->methodAttributeConfigurators || $this->parameterAttributeConfigurators) {
|
||||
foreach ($classReflector->getMethods(\ReflectionMethod::IS_PUBLIC) as $methodReflector) {
|
||||
if ($methodReflector->isConstructor() || $methodReflector->isDestructor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->methodAttributeConfigurators) {
|
||||
foreach ($methodReflector->getAttributes() as $attribute) {
|
||||
if ($configurator = $this->methodAttributeConfigurators[$attribute->getName()] ?? null) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $methodReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->parameterAttributeConfigurators) {
|
||||
foreach ($methodReflector->getParameters() as $parameterReflector) {
|
||||
foreach ($parameterReflector->getAttributes() as $attribute) {
|
||||
if ($configurator = $this->parameterAttributeConfigurators[$attribute->getName()] ?? null) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $parameterReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->propertyAttributeConfigurators) {
|
||||
foreach ($classReflector->getProperties(\ReflectionProperty::IS_PUBLIC) as $propertyReflector) {
|
||||
if ($propertyReflector->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($propertyReflector->getAttributes() as $attribute) {
|
||||
if ($configurator = $this->propertyAttributeConfigurators[$attribute->getName()] ?? null) {
|
||||
$configurator($conditionals, $attribute->newInstance(), $propertyReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($instanceof[$classReflector->getName()]) && new ChildDefinition('') != $conditionals) {
|
||||
$instanceof[$classReflector->getName()] = $conditionals;
|
||||
$value->setInstanceofConditionals($instanceof);
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
42
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutoAliasServicePass.php
vendored
Normal file
42
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutoAliasServicePass.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\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
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowireAsDecoratorPass.php
vendored
Normal file
46
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowireAsDecoratorPass.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\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 $definition) {
|
||||
if ($this->accept($definition) && $reflectionClass = $container->getReflectionClass($definition->getClass(), false)) {
|
||||
$this->processClass($definition, $reflectionClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function accept(Definition $definition): bool
|
||||
{
|
||||
return !$definition->hasTag('container.ignore_attributes') && $definition->isAutowired();
|
||||
}
|
||||
|
||||
private function processClass(Definition $definition, \ReflectionClass $reflectionClass): void
|
||||
{
|
||||
foreach ($reflectionClass->getAttributes(AsDecorator::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
|
||||
$attribute = $attribute->newInstance();
|
||||
|
||||
$definition->setDecoratedService($attribute->decorates, null, $attribute->priority, $attribute->onInvalid);
|
||||
}
|
||||
}
|
||||
}
|
746
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowirePass.php
vendored
Normal file
746
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowirePass.php
vendored
Normal file
@@ -0,0 +1,746 @@
|
||||
<?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\AutowireCallable;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
|
||||
use Symfony\Component\DependencyInjection\Attribute\MapDecorated;
|
||||
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 bool $throwOnAutowiringException;
|
||||
private ?string $decoratedClass = null;
|
||||
private ?string $decoratedId = null;
|
||||
private ?array $methodCalls = null;
|
||||
private object $defaultArgument;
|
||||
private ?\Closure $getPreviousValue = null;
|
||||
private ?int $decoratedMethodIndex = null;
|
||||
private ?int $decoratedMethodArgumentIndex = null;
|
||||
private ?self $typesClone = null;
|
||||
|
||||
public function __construct(bool $throwOnAutowireException = true)
|
||||
{
|
||||
$this->throwOnAutowiringException = $throwOnAutowireException;
|
||||
$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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->defaultArgument->bag = $container->getParameterBag();
|
||||
|
||||
try {
|
||||
$this->typesClone = clone $this;
|
||||
parent::process($container);
|
||||
} finally {
|
||||
$this->decoratedClass = null;
|
||||
$this->decoratedId = null;
|
||||
$this->methodCalls = null;
|
||||
$this->defaultArgument->bag = null;
|
||||
$this->defaultArgument->names = null;
|
||||
$this->getPreviousValue = null;
|
||||
$this->decoratedMethodIndex = null;
|
||||
$this->decoratedMethodArgumentIndex = 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 || $value instanceof MapDecorated) {
|
||||
$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;
|
||||
}
|
||||
|
||||
$this->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($this->methodCalls, [$constructor, $value->getArguments()]);
|
||||
}
|
||||
|
||||
$checkAttributes = !$value->hasTag('container.ignore_attributes');
|
||||
$this->methodCalls = $this->autowireCalls($reflectionClass, $isRoot, $checkAttributes);
|
||||
|
||||
if ($constructor) {
|
||||
[, $arguments] = array_shift($this->methodCalls);
|
||||
|
||||
if ($arguments !== $value->getArguments()) {
|
||||
$value->setArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->methodCalls !== $value->getMethodCalls()) {
|
||||
$value->setMethodCalls($this->methodCalls);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot, bool $checkAttributes): array
|
||||
{
|
||||
$this->decoratedId = null;
|
||||
$this->decoratedClass = null;
|
||||
$this->getPreviousValue = null;
|
||||
|
||||
if ($isRoot && ($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 ($this->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, $i);
|
||||
|
||||
if ($arguments !== $call[1]) {
|
||||
$this->methodCalls[$i][1] = $arguments;
|
||||
$patchedIndexes[] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// use named arguments to skip complex default values
|
||||
foreach ($patchedIndexes as $i) {
|
||||
$namedArguments = null;
|
||||
$arguments = $this->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;
|
||||
}
|
||||
}
|
||||
|
||||
$this->methodCalls[$i][1] = $arguments;
|
||||
}
|
||||
|
||||
return $this->methodCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowires the constructor or a method.
|
||||
*
|
||||
* @throws AutowiringFailedException
|
||||
*/
|
||||
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes, int $methodIndex): array
|
||||
{
|
||||
$class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId;
|
||||
$method = $reflectionMethod->name;
|
||||
$parameters = $reflectionMethod->getParameters();
|
||||
if ($reflectionMethod->isVariadic()) {
|
||||
array_pop($parameters);
|
||||
}
|
||||
$this->defaultArgument->names = new \ArrayObject();
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
$this->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] : [];
|
||||
|
||||
$getValue = function () use ($type, $parameter, $class, $method, $name, $target) {
|
||||
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 !== $this->currentId ? $class.'::'.$method : $method));
|
||||
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$value = $this->defaultArgument->withValue($parameter);
|
||||
} elseif (!$parameter->allowsNull()) {
|
||||
throw new AutowiringFailedException($this->currentId, $failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
|
||||
if ($checkAttributes) {
|
||||
foreach ($parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
|
||||
$attribute = $attribute->newInstance();
|
||||
$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 $this->defaultArgument;
|
||||
$arguments[$index]->value = $parameter->getDefaultValue();
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if ($attribute instanceof AutowireCallable) {
|
||||
$value = $attribute->buildDefinition($value, $type, $parameter);
|
||||
} elseif ($lazy = $attribute->lazy) {
|
||||
$definition = (new Definition($type))
|
||||
->setFactory('current')
|
||||
->setArguments([[$value ??= $getValue()]])
|
||||
->setLazy(true);
|
||||
|
||||
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) : [];
|
||||
}
|
||||
|
||||
if ($lazy) {
|
||||
if (!class_exists($type) && !interface_exists($type, 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;
|
||||
}
|
||||
|
||||
foreach ($parameter->getAttributes(MapDecorated::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] = $this->defaultArgument->withValue($parameter);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->decoratedClass && is_a($this->decoratedClass, $type, true)) {
|
||||
if ($this->getPreviousValue) {
|
||||
// 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.
|
||||
|
||||
$getPreviousValue = $this->getPreviousValue;
|
||||
$this->methodCalls[$this->decoratedMethodIndex][1][$this->decoratedMethodArgumentIndex] = $getPreviousValue();
|
||||
$this->decoratedClass = null; // Prevent further checks
|
||||
} else {
|
||||
$arguments[$index] = new TypedReference($this->decoratedId, $this->decoratedClass);
|
||||
$this->getPreviousValue = $getValue;
|
||||
$this->decoratedMethodIndex = $methodIndex;
|
||||
$this->decoratedMethodArgumentIndex = $index;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$arguments[$index] = $getValue();
|
||||
}
|
||||
|
||||
if ($parameters && !isset($arguments[++$index])) {
|
||||
while (0 <= --$index) {
|
||||
if (!$arguments[$index] instanceof $this->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 ($this->container->has($alias = $type.' $'.$name) && !$this->container->findDefinition($alias)->isAbstract()) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
if (null !== ($alias = $this->getCombinedAlias($type, $name)) && !$this->container->findDefinition($alias)->isAbstract()) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
$parsedName = (new Target($name))->getParsedName();
|
||||
|
||||
if ($this->container->has($alias = $type.' $'.$parsedName) && !$this->container->findDefinition($alias)->isAbstract()) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
if (null !== ($alias = $this->getCombinedAlias($type, $parsedName)) && !$this->container->findDefinition($alias)->isAbstract()) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
if (($this->container->has($n = $name) && !$this->container->findDefinition($n)->isAbstract())
|
||||
|| ($this->container->has($n = $parsedName) && !$this->container->findDefinition($n)->isAbstract())
|
||||
) {
|
||||
foreach ($this->container->getAliases() as $id => $alias) {
|
||||
if ($n === (string) $alias && str_starts_with($id, $type.' $')) {
|
||||
return new TypedReference($n, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $target) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
|
||||
return new TypedReference($type, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
if (null !== ($alias = $this->getCombinedAlias($type)) && !$this->container->findDefinition($alias)->isAbstract()) {
|
||||
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 a 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) && !$container->findDefinition($parent)->isAbstract()) {
|
||||
$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]);
|
||||
}
|
||||
$message .= sprintf('or %s "%s".', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
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.' $')
|
||||
&& (new Target($target = substr($target, \strlen($type) + 3)))->getParsedName() === $name
|
||||
) {
|
||||
$name = $target;
|
||||
}
|
||||
|
||||
$this->autowiringAliases[$type][$name] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
private function getCombinedAlias(string $type, ?string $name = null): ?string
|
||||
{
|
||||
if (str_contains($type, '&')) {
|
||||
$types = explode('&', $type);
|
||||
} elseif (str_contains($type, '|')) {
|
||||
$types = explode('|', $type);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$alias = null;
|
||||
$suffix = $name ? ' $'.$name : '';
|
||||
|
||||
foreach ($types as $type) {
|
||||
if (!$this->container->hasAlias($type.$suffix)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null === $alias) {
|
||||
$alias = (string) $this->container->getAlias($type.$suffix);
|
||||
} elseif ((string) $this->container->getAlias($type.$suffix) !== $alias) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
}
|
110
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php
vendored
Normal file
110
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.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\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 (false !== $doc = $r->getDocComment()) {
|
||||
if (false !== stripos($doc, '@required') && preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@required(?:\s|\*/$)#i', $doc)) {
|
||||
trigger_deprecation('symfony/dependency-injection', '6.3', 'Relying on the "@required" annotation on method "%s::%s()" is deprecated, use the "Symfony\Contracts\Service\Attribute\Required" attribute instead.', $reflectionMethod->class, $reflectionMethod->name);
|
||||
|
||||
if ($this->isWither($reflectionMethod, $doc)) {
|
||||
$withers[] = [$reflectionMethod->name, [], true];
|
||||
} else {
|
||||
$value->addMethodCall($reflectionMethod->name, []);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (false === stripos($doc, '@inheritdoc') || !preg_match('#(?:^/\*\*|\n\s*+\*)\s*+(?:\{@inheritdoc\}|@inheritdoc)(?:\s|\*/$)#i', $doc)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
$r = $r->getPrototype();
|
||||
} catch (\ReflectionException) {
|
||||
break; // method has no prototype
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
<?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\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;
|
||||
}
|
||||
$doc = false;
|
||||
if (!$reflectionProperty->getAttributes(Required::class)
|
||||
&& ((false === $doc = $reflectionProperty->getDocComment()) || false === stripos($doc, '@required') || !preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@required(?:\s|\*/$)#i', $doc))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if ($doc) {
|
||||
trigger_deprecation('symfony/dependency-injection', '6.3', 'Using the "@required" annotation on property "%s::$%s" is deprecated, use the "Symfony\Contracts\Service\Attribute\Required" attribute instead.', $reflectionProperty->class, $reflectionProperty->name);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
118
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php
vendored
Normal file
118
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?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;
|
||||
|
||||
private bool $throwExceptions;
|
||||
|
||||
public function __construct(bool $throwExceptions = true)
|
||||
{
|
||||
$this->throwExceptions = $throwExceptions;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Checks the ContainerBuilder object for circular references.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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])) {
|
||||
// Don't check circular references for lazy edges
|
||||
if (!$node->getValue() || (!$edge->isLazy() && !$edge->isWeak())) {
|
||||
$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;
|
||||
array_pop($this->currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php
vendored
Normal file
100
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?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.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException When the Definition is invalid
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
// 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() && !$definition->isPrivate()) {
|
||||
$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() && !$alias->isPrivate()) {
|
||||
$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,128 @@
|
||||
<?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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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($id = (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, $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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
334
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php
vendored
Normal file
334
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
<?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 bool $autoload;
|
||||
private array $skippedIds;
|
||||
|
||||
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(bool $autoload = false, array $skippedIds = [])
|
||||
{
|
||||
$this->autoload = $autoload;
|
||||
$this->skippedIds = $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;
|
||||
}
|
||||
if (\array_key_exists($p->name, $values)) {
|
||||
$i = $p->name;
|
||||
} elseif (!\array_key_exists($i, $values)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->checkType($checkedDefinition, $values[$i], $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 && method_exists($class, '__toString')) {
|
||||
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());
|
||||
}
|
||||
}
|
104
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/Compiler.php
vendored
Normal file
104
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/Compiler.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\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addPass(CompilerPassInterface $pass, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0)
|
||||
{
|
||||
$this->passConfig->addPass($pass, $type, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @final
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log(CompilerPassInterface $pass, string $message)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function compile(ContainerBuilder $container)
|
||||
{
|
||||
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
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/CompilerPassInterface.php
vendored
Normal file
29
plugins/simplesaml/lib/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);
|
||||
}
|
133
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
vendored
Normal file
133
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php
vendored
Normal file
110
plugins/simplesaml/lib/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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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()) {
|
||||
$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;
|
||||
}
|
||||
}
|
37
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php
vendored
Normal file
37
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ExtensionCompilerPass.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\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* A pass to automatically process extensions if they implement
|
||||
* CompilerPassInterface.
|
||||
*
|
||||
* @author Wouter J <wouter@wouterj.nl>
|
||||
*/
|
||||
class ExtensionCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if (!$extension instanceof CompilerPassInterface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension->process($container);
|
||||
}
|
||||
}
|
||||
}
|
229
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php
vendored
Normal file
229
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
<?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 ?AnalyzeServiceReferencesPass $analyzingPass;
|
||||
private array $cloningIds = [];
|
||||
private array $connectedIds = [];
|
||||
private array $notInlinedIds = [];
|
||||
private array $inlinedIds = [];
|
||||
private array $notInlinableIds = [];
|
||||
private ?ServiceReferenceGraph $graph = null;
|
||||
|
||||
public function __construct(?AnalyzeServiceReferencesPass $analyzingPass = null)
|
||||
{
|
||||
$this->analyzingPass = $analyzingPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
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);
|
||||
$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 ($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()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->graph->hasNode($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->currentId === $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;
|
||||
}
|
||||
|
||||
return $this->container->getDefinition($srcId)->isShared();
|
||||
}
|
||||
}
|
@@ -0,0 +1,207 @@
|
||||
<?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\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
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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());
|
||||
}
|
||||
}
|
||||
$config = $resolvingBag->resolveValue($config);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, $format, $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, $format, $usedEnvs);
|
||||
}
|
||||
}
|
287
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/PassConfig.php
vendored
Normal file
287
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/PassConfig.php
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
<?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
|
||||
{
|
||||
public const TYPE_AFTER_REMOVING = 'afterRemoving';
|
||||
public const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization';
|
||||
public const TYPE_BEFORE_REMOVING = 'beforeRemoving';
|
||||
public const TYPE_OPTIMIZE = 'optimization';
|
||||
public const TYPE_REMOVE = 'removing';
|
||||
|
||||
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 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
|
||||
-2048 => [new RemoveBuildParametersPass()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException when a pass type doesn't exist
|
||||
*/
|
||||
public function addPass(CompilerPassInterface $pass, string $type = self::TYPE_BEFORE_OPTIMIZATION, int $priority = 0)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setMergePass(CompilerPassInterface $pass)
|
||||
{
|
||||
$this->mergePass = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AfterRemoving passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAfterRemovingPasses(array $passes)
|
||||
{
|
||||
$this->afterRemovingPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeOptimization passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setBeforeOptimizationPasses(array $passes)
|
||||
{
|
||||
$this->beforeOptimizationPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeRemoving passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setBeforeRemovingPasses(array $passes)
|
||||
{
|
||||
$this->beforeRemovingPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Optimization passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setOptimizationPasses(array $passes)
|
||||
{
|
||||
$this->optimizationPasses = [$passes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Removing passes.
|
||||
*
|
||||
* @param CompilerPassInterface[] $passes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setRemovingPasses(array $passes)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
176
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php
vendored
Normal file
176
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
<?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();
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$services = [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
||||
if (\in_array($serviceId, $exclude, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaultPriority = null;
|
||||
$defaultIndex = null;
|
||||
$definition = $container->getDefinition($serviceId);
|
||||
$class = $definition->getClass();
|
||||
$class = $container->getParameterBag()->resolveValue($class) ?: null;
|
||||
$checkTaggedItem = !$definition->hasTag($definition->isAutoconfigured() ? 'container.ignore_attributes' : $tagName);
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$index = $priority = null;
|
||||
|
||||
if (isset($attribute['priority'])) {
|
||||
$priority = $attribute['priority'];
|
||||
} elseif (null === $defaultPriority && $defaultPriorityMethod && $class) {
|
||||
$defaultPriority = PriorityTaggedServiceUtil::getDefault($container, $serviceId, $class, $defaultPriorityMethod, $tagName, 'priority', $checkTaggedItem);
|
||||
}
|
||||
$priority ??= $defaultPriority ??= 0;
|
||||
|
||||
if (null === $indexAttribute && !$defaultIndexMethod && !$needsIndexes) {
|
||||
$services[] = [$priority, ++$i, null, $serviceId, null];
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if (null !== $indexAttribute && isset($attribute[$indexAttribute])) {
|
||||
$index = $attribute[$indexAttribute];
|
||||
} elseif (null === $defaultIndex && $defaultPriorityMethod && $class) {
|
||||
$defaultIndex = PriorityTaggedServiceUtil::getDefault($container, $serviceId, $class, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute, $checkTaggedItem);
|
||||
}
|
||||
$decorated = $definition->getTag('container.decorator')[0]['id'] ?? null;
|
||||
$index = $index ?? $defaultIndex ?? $defaultIndex = $decorated ?? $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]) {
|
||||
if (!$class) {
|
||||
$reference = new Reference($serviceId);
|
||||
} elseif ($index === $serviceId) {
|
||||
$reference = new TypedReference($serviceId, $class);
|
||||
} else {
|
||||
$reference = 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(ContainerBuilder $container, string $serviceId, string $class, string $defaultMethod, string $tagName, ?string $indexAttribute, bool $checkTaggedItem): string|int|null
|
||||
{
|
||||
if (!($r = $container->getReflectionClass($class)) || (!$checkTaggedItem && !$r->hasMethod($defaultMethod))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($checkTaggedItem && !$r->hasMethod($defaultMethod)) {
|
||||
foreach ($r->getAttributes(AsTaggedItem::class) as $attribute) {
|
||||
return 'priority' === $indexAttribute ? $attribute->newInstance()->priority : $attribute->newInstance()->index;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($r->isInterface()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
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
|
||||
{
|
||||
foreach ($class->getAttributes(Autoconfigure::class, \ReflectionAttribute::IS_INSTANCEOF) 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 ($attribute['tags'] ?? [] as $i => $tag) {
|
||||
if (\is_array($tag) && [0] === array_keys($tag)) {
|
||||
$attribute['tags'][$i] = [$class->name => $tag[0]];
|
||||
}
|
||||
}
|
||||
|
||||
$parseDefinitions->invoke(
|
||||
$yamlLoader,
|
||||
[
|
||||
'services' => [
|
||||
'_instanceof' => [
|
||||
$class->name => [$container->registerForAutoconfiguration($class->name)] + $attribute,
|
||||
],
|
||||
],
|
||||
],
|
||||
$class->getFileName(),
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
(self::$registerForAutoconfiguration)($container, $class, $attribute);
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
<?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];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid type "%s" returned by "%s::getProvidedTypes()", expected one of "%s".', $type, $class, implode('", "', self::ALLOWED_TYPES)));
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
}
|
@@ -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\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
|
||||
{
|
||||
private bool $beforeRemoving;
|
||||
|
||||
public function __construct(bool $beforeRemoving)
|
||||
{
|
||||
$this->beforeRemoving = $beforeRemoving;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
<?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\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
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\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Contracts\Service\Attribute\SubscribedService;
|
||||
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;
|
||||
// to remove when symfony/dependency-injection will stop being compatible with symfony/framework-bundle<6.0
|
||||
$replaceDeprecatedSession = $this->container->has('.session.deprecated') && $r->isSubclassOf(AbstractController::class);
|
||||
$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));
|
||||
}
|
||||
if ($replaceDeprecatedSession && SessionInterface::class === $type) {
|
||||
// This prevents triggering the deprecation when building the container
|
||||
// to remove when symfony/dependency-injection will stop being compatible with symfony/framework-bundle<6.0
|
||||
$type = '.session.deprecated';
|
||||
}
|
||||
$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),
|
||||
] + $value->getBindings());
|
||||
|
||||
return parent::processValue($value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isAbstract()) {
|
||||
$container->removeDefinition($id);
|
||||
$container->log($this, sprintf('Removed service "%s"; reason: abstract.', $id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
<?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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$parameterBag = $container->getParameterBag();
|
||||
$this->removedParameters = [];
|
||||
|
||||
foreach ($parameterBag->all() as $name => $value) {
|
||||
if ('.' === ($name[0] ?? '')) {
|
||||
$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;
|
||||
}
|
||||
}
|
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php
vendored
Normal file
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($alias->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container->removeAlias($id);
|
||||
$container->log($this, sprintf('Removed service "%s"; reason: private alias.', $id));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
<?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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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\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.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException if the service definition does not exist
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
// First collect all alias targets that need to be replaced
|
||||
$seenAliasTargets = [];
|
||||
$replacements = [];
|
||||
|
||||
foreach ($container->getAliases() 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);
|
||||
}
|
||||
}
|
271
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php
vendored
Normal file
271
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
<?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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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)
|
||||
)) {
|
||||
$arguments[$key] = $this->getBindingValue($bindings[$k]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\array_key_exists($k = '$'.$name, $bindings) || \array_key_exists($k = '$'.$parsedName, $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 (isset($bindingNames[$name]) || isset($bindingNames[$parsedName]) || isset($bindingNames[$parameter->name])) {
|
||||
$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
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php
vendored
Normal file
201
plugins/simplesaml/lib/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;
|
||||
}
|
||||
}
|
40
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php
vendored
Normal file
40
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isSynthetic() || null !== $definition->getClass()) {
|
||||
continue;
|
||||
}
|
||||
if (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)) {
|
||||
if ($definition instanceof ChildDefinition && !class_exists($id)) {
|
||||
throw new InvalidArgumentException(sprintf('Service definition "%s" has a parent but no class, and its name looks like an 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));
|
||||
}
|
||||
$definition->setClass($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveDecoratorStackPass.php
vendored
Normal file
123
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveDecoratorStackPass.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
@@ -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\Definition;
|
||||
|
||||
/**
|
||||
* Replaces env var placeholders by their current values.
|
||||
*/
|
||||
class ResolveEnvPlaceholdersPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = false;
|
||||
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if (\is_string($value)) {
|
||||
return $this->container->resolveEnvPlaceholders($value, true);
|
||||
}
|
||||
if ($value instanceof Definition) {
|
||||
$changes = $value->getChanges();
|
||||
if (isset($changes['class'])) {
|
||||
$value->setClass($this->container->resolveEnvPlaceholders($value->getClass(), true));
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$value->setFile($this->container->resolveEnvPlaceholders($value->getFile(), true));
|
||||
}
|
||||
}
|
||||
|
||||
$value = parent::processValue($value, $isRoot);
|
||||
|
||||
if ($value && \is_array($value) && !$isRoot) {
|
||||
$value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), true), $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
37
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveFactoryClassPass.php
vendored
Normal file
37
plugins/simplesaml/lib/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);
|
||||
}
|
||||
}
|
79
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php
vendored
Normal file
79
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
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))) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
136
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php
vendored
Normal file
136
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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()) {
|
||||
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
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php
vendored
Normal file
137
plugins/simplesaml/lib/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);
|
||||
}
|
||||
}
|
93
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveNoPreloadPass.php
vendored
Normal file
93
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ResolveNoPreloadPass.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\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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
try {
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isPublic() && !$definition->isPrivate() && !isset($this->resolvedIds[$id])) {
|
||||
$this->resolvedIds[$id] = true;
|
||||
$this->processValue($definition, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $alias) {
|
||||
if ($alias->isPublic() && !$alias->isPrivate() && !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->isPublic() || $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);
|
||||
}
|
||||
}
|
@@ -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\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,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws ParameterNotFoundException
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
parent::process($container);
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$aliasId = (string) $alias;
|
||||
$this->currentId = $id;
|
||||
|
||||
if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) {
|
||||
$container->setAlias($id, $defId)->setPublic($alias->isPublic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
137
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
vendored
Normal file
137
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.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\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);
|
||||
}
|
||||
|
||||
$services = $value->getArguments()[0] ?? null;
|
||||
|
||||
if ($services instanceof TaggedIteratorArgument) {
|
||||
$services = $this->findAndSortTaggedServices($services, $this->container);
|
||||
}
|
||||
|
||||
if (!\is_array($services)) {
|
||||
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));
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
|
||||
foreach ($services as $k => $v) {
|
||||
if ($v instanceof ServiceClosureArgument) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($i === $k) {
|
||||
if ($v instanceof Reference) {
|
||||
unset($services[$k]);
|
||||
$k = (string) $v;
|
||||
}
|
||||
++$i;
|
||||
} elseif (\is_int($k)) {
|
||||
$i = null;
|
||||
}
|
||||
|
||||
$services[$k] = new ServiceClosureArgument($v);
|
||||
}
|
||||
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
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php
vendored
Normal file
99
plugins/simplesaml/lib/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): 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);
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
<?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
|
||||
{
|
||||
private ServiceReferenceGraphNode $sourceNode;
|
||||
private ServiceReferenceGraphNode $destNode;
|
||||
private mixed $value;
|
||||
private bool $lazy;
|
||||
private bool $weak;
|
||||
private bool $byConstructor;
|
||||
|
||||
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, mixed $value = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false)
|
||||
{
|
||||
$this->sourceNode = $sourceNode;
|
||||
$this->destNode = $destNode;
|
||||
$this->value = $value;
|
||||
$this->lazy = $lazy;
|
||||
$this->weak = $weak;
|
||||
$this->byConstructor = $byConstructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
114
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php
vendored
Normal file
114
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?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 string $id;
|
||||
private array $inEdges = [];
|
||||
private array $outEdges = [];
|
||||
private mixed $value;
|
||||
|
||||
public function __construct(string $id, mixed $value)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addInEdge(ServiceReferenceGraphEdge $edge)
|
||||
{
|
||||
$this->inEdges[] = $edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addOutEdge(ServiceReferenceGraphEdge $edge)
|
||||
{
|
||||
$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.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->inEdges = $this->outEdges = [];
|
||||
}
|
||||
}
|
103
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php
vendored
Normal file
103
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.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\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 = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$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 = [];
|
||||
if (false === $i = strpos($env, ':')) {
|
||||
$default = $defaultBag->has("env($env)") ? $defaultBag->get("env($env)") : self::TYPE_FIXTURES['string'];
|
||||
$defaultType = null !== $default ? get_debug_type($default) : 'string';
|
||||
$values[$defaultType] = $default;
|
||||
} else {
|
||||
$prefix = substr($env, 0, $i);
|
||||
foreach ($envTypes[$prefix] ?? ['string'] as $type) {
|
||||
$values[$type] = self::TYPE_FIXTURES[$type] ?? null;
|
||||
}
|
||||
}
|
||||
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 = [];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?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\Config;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Tracks container parameters.
|
||||
*
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ContainerParametersResource implements ResourceInterface
|
||||
{
|
||||
private array $parameters;
|
||||
|
||||
/**
|
||||
* @param array $parameters The container parameters to track
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'container_parameters_'.hash('xxh128', serialize($this->parameters));
|
||||
}
|
||||
|
||||
public function getParameters(): array
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
}
|
@@ -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\Config;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Config\ResourceCheckerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*/
|
||||
class ContainerParametersResourceChecker implements ResourceCheckerInterface
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function supports(ResourceInterface $metadata): bool
|
||||
{
|
||||
return $metadata instanceof ContainerParametersResource;
|
||||
}
|
||||
|
||||
public function isFresh(ResourceInterface $resource, int $timestamp): bool
|
||||
{
|
||||
foreach ($resource->getParameters() as $key => $value) {
|
||||
if (!$this->container->hasParameter($key) || $this->container->getParameter($key) !== $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
416
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Container.php
vendored
Normal file
416
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Container.php
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
// Help opcache.preload discover always-needed symbols
|
||||
class_exists(RewindableGenerator::class);
|
||||
class_exists(ArgumentServiceLocator::class);
|
||||
|
||||
/**
|
||||
* Container is a dependency injection container.
|
||||
*
|
||||
* It gives access to object instances (services).
|
||||
* Services and parameters are simple key/pair stores.
|
||||
* The container can have four possible behaviors when a service
|
||||
* does not exist (or is not initialized for the last case):
|
||||
*
|
||||
* * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception at compilation time (the default)
|
||||
* * NULL_ON_INVALID_REFERENCE: Returns null
|
||||
* * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
|
||||
* (for instance, ignore a setter if the service does not exist)
|
||||
* * IGNORE_ON_UNINITIALIZED_REFERENCE: Ignores/returns null for uninitialized services or invalid references
|
||||
* * RUNTIME_EXCEPTION_ON_INVALID_REFERENCE: Throws an exception at runtime
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Container implements ContainerInterface, ResetInterface
|
||||
{
|
||||
protected $parameterBag;
|
||||
protected $services = [];
|
||||
protected $privates = [];
|
||||
protected $fileMap = [];
|
||||
protected $methodMap = [];
|
||||
protected $factories = [];
|
||||
protected $aliases = [];
|
||||
protected $loading = [];
|
||||
protected $resolving = [];
|
||||
protected $syntheticIds = [];
|
||||
|
||||
private array $envCache = [];
|
||||
private bool $compiled = false;
|
||||
private \Closure $getEnv;
|
||||
|
||||
private static \Closure $make;
|
||||
|
||||
public function __construct(?ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
$this->parameterBag = $parameterBag ?? new EnvPlaceholderParameterBag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the container.
|
||||
*
|
||||
* This method does two things:
|
||||
*
|
||||
* * Parameter values are resolved;
|
||||
* * The parameter bag is frozen.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
$this->parameterBag->resolve();
|
||||
|
||||
$this->parameterBag = new FrozenParameterBag(
|
||||
$this->parameterBag->all(),
|
||||
$this->parameterBag instanceof ParameterBag ? $this->parameterBag->allDeprecated() : []
|
||||
);
|
||||
|
||||
$this->compiled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the container is compiled.
|
||||
*/
|
||||
public function isCompiled(): bool
|
||||
{
|
||||
return $this->compiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service container parameter bag.
|
||||
*/
|
||||
public function getParameterBag(): ParameterBagInterface
|
||||
{
|
||||
return $this->parameterBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parameter.
|
||||
*
|
||||
* @return array|bool|string|int|float|\UnitEnum|null
|
||||
*
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*/
|
||||
public function getParameter(string $name)
|
||||
{
|
||||
return $this->parameterBag->get($name);
|
||||
}
|
||||
|
||||
public function hasParameter(string $name): bool
|
||||
{
|
||||
return $this->parameterBag->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setParameter(string $name, array|bool|string|int|float|\UnitEnum|null $value)
|
||||
{
|
||||
$this->parameterBag->set($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a service.
|
||||
*
|
||||
* Setting a synthetic service to null resets it: has() returns false and get()
|
||||
* behaves in the same way as if the service was never created.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $id, ?object $service)
|
||||
{
|
||||
// Runs the internal initializer; used by the dumped container to include always-needed files
|
||||
if (isset($this->privates['service_container']) && $this->privates['service_container'] instanceof \Closure) {
|
||||
$initialize = $this->privates['service_container'];
|
||||
unset($this->privates['service_container']);
|
||||
$initialize($this);
|
||||
}
|
||||
|
||||
if ('service_container' === $id) {
|
||||
throw new InvalidArgumentException('You cannot set service "service_container".');
|
||||
}
|
||||
|
||||
if (!(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) {
|
||||
if (isset($this->syntheticIds[$id]) || !isset($this->getRemovedIds()[$id])) {
|
||||
// no-op
|
||||
} elseif (null === $service) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" service is private, you cannot unset it.', $id));
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" service is private, you cannot replace it.', $id));
|
||||
}
|
||||
} elseif (isset($this->services[$id])) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" service is already initialized, you cannot replace it.', $id));
|
||||
}
|
||||
|
||||
if (isset($this->aliases[$id])) {
|
||||
unset($this->aliases[$id]);
|
||||
}
|
||||
|
||||
if (null === $service) {
|
||||
unset($this->services[$id]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->services[$id] = $service;
|
||||
}
|
||||
|
||||
public function has(string $id): bool
|
||||
{
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
if (isset($this->services[$id])) {
|
||||
return true;
|
||||
}
|
||||
if ('service_container' === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset($this->fileMap[$id]) || isset($this->methodMap[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service.
|
||||
*
|
||||
* @throws ServiceCircularReferenceException When a circular reference is detected
|
||||
* @throws ServiceNotFoundException When the service is not defined
|
||||
*
|
||||
* @see Reference
|
||||
*/
|
||||
public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE): ?object
|
||||
{
|
||||
return $this->services[$id]
|
||||
?? $this->services[$id = $this->aliases[$id] ?? $id]
|
||||
?? ('service_container' === $id ? $this : ($this->factories[$id] ?? self::$make ??= self::make(...))($this, $id, $invalidBehavior));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a service.
|
||||
*
|
||||
* As a separate method to allow "get()" to use the really fast `??` operator.
|
||||
*/
|
||||
private static function make(self $container, string $id, int $invalidBehavior): ?object
|
||||
{
|
||||
if (isset($container->loading[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, array_merge(array_keys($container->loading), [$id]));
|
||||
}
|
||||
|
||||
$container->loading[$id] = true;
|
||||
|
||||
try {
|
||||
if (isset($container->fileMap[$id])) {
|
||||
return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $container->load($container->fileMap[$id]);
|
||||
} elseif (isset($container->methodMap[$id])) {
|
||||
return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $container->{$container->methodMap[$id]}($container);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
unset($container->services[$id]);
|
||||
|
||||
throw $e;
|
||||
} finally {
|
||||
unset($container->loading[$id]);
|
||||
}
|
||||
|
||||
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
if (!$id) {
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
if (isset($container->syntheticIds[$id])) {
|
||||
throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service is synthetic, it needs to be set at boot time before it can be used.', $id));
|
||||
}
|
||||
if (isset($container->getRemovedIds()[$id])) {
|
||||
throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.', $id));
|
||||
}
|
||||
|
||||
$alternatives = [];
|
||||
foreach ($container->getServiceIds() as $knownId) {
|
||||
if ('' === $knownId || '.' === $knownId[0]) {
|
||||
continue;
|
||||
}
|
||||
$lev = levenshtein($id, $knownId);
|
||||
if ($lev <= \strlen($id) / 3 || str_contains($knownId, $id)) {
|
||||
$alternatives[] = $knownId;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ServiceNotFoundException($id, null, null, $alternatives);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service has actually been initialized.
|
||||
*/
|
||||
public function initialized(string $id): bool
|
||||
{
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
|
||||
if ('service_container' === $id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($this->services[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$services = $this->services + $this->privates;
|
||||
|
||||
foreach ($services as $service) {
|
||||
try {
|
||||
if ($service instanceof ResetInterface) {
|
||||
$service->reset();
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->services = $this->factories = $this->privates = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all service ids.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getServiceIds(): array
|
||||
{
|
||||
return array_map('strval', array_unique(array_merge(['service_container'], array_keys($this->fileMap), array_keys($this->methodMap), array_keys($this->aliases), array_keys($this->services))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets service ids that existed at compile time.
|
||||
*/
|
||||
public function getRemovedIds(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Camelizes a string.
|
||||
*/
|
||||
public static function camelize(string $id): string
|
||||
{
|
||||
return strtr(ucwords(strtr($id, ['_' => ' ', '.' => '_ ', '\\' => '_ '])), [' ' => '']);
|
||||
}
|
||||
|
||||
/**
|
||||
* A string to underscore.
|
||||
*/
|
||||
public static function underscore(string $id): string
|
||||
{
|
||||
return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], str_replace('_', '.', $id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a service by requiring its factory file.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function load(string $file)
|
||||
{
|
||||
return require $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a variable from the environment.
|
||||
*
|
||||
* @throws EnvNotFoundException When the environment variable is not found and has no default value
|
||||
*/
|
||||
protected function getEnv(string $name): mixed
|
||||
{
|
||||
if (isset($this->resolving[$envName = "env($name)"])) {
|
||||
throw new ParameterCircularReferenceException(array_keys($this->resolving));
|
||||
}
|
||||
if (isset($this->envCache[$name]) || \array_key_exists($name, $this->envCache)) {
|
||||
return $this->envCache[$name];
|
||||
}
|
||||
if (!$this->has($id = 'container.env_var_processors_locator')) {
|
||||
$this->set($id, new ServiceLocator([]));
|
||||
}
|
||||
$this->getEnv ??= $this->getEnv(...);
|
||||
$processors = $this->get($id);
|
||||
|
||||
if (false !== $i = strpos($name, ':')) {
|
||||
$prefix = substr($name, 0, $i);
|
||||
$localName = substr($name, 1 + $i);
|
||||
} else {
|
||||
$prefix = 'string';
|
||||
$localName = $name;
|
||||
}
|
||||
|
||||
$processor = $processors->has($prefix) ? $processors->get($prefix) : new EnvVarProcessor($this);
|
||||
if (false === $i) {
|
||||
$prefix = '';
|
||||
}
|
||||
|
||||
$this->resolving[$envName] = true;
|
||||
try {
|
||||
return $this->envCache[$name] = $processor->getEnv($prefix, $localName, $this->getEnv);
|
||||
} finally {
|
||||
unset($this->resolving[$envName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final protected function getService(string|false $registry, string $id, ?string $method, string|bool $load): mixed
|
||||
{
|
||||
if ('service_container' === $id) {
|
||||
return $this;
|
||||
}
|
||||
if (\is_string($load)) {
|
||||
throw new RuntimeException($load);
|
||||
}
|
||||
if (null === $method) {
|
||||
return false !== $registry ? $this->{$registry}[$id] ?? null : null;
|
||||
}
|
||||
if (false !== $registry) {
|
||||
return $this->{$registry}[$id] ??= $load ? $this->load($method) : $this->{$method}($this);
|
||||
}
|
||||
if (!$load) {
|
||||
return $this->{$method}($this);
|
||||
}
|
||||
|
||||
return ($factory = $this->factories[$id] ?? $this->factories['service_container'][$id] ?? null) ? $factory($this) : $this->load($method);
|
||||
}
|
||||
|
||||
private function __clone()
|
||||
{
|
||||
}
|
||||
}
|
29
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerAwareInterface.php
vendored
Normal file
29
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerAwareInterface.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;
|
||||
|
||||
/**
|
||||
* ContainerAwareInterface should be implemented by classes that depends on a Container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 6.4, use dependency injection instead
|
||||
*/
|
||||
interface ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Sets the container.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setContainer(?ContainerInterface $container);
|
||||
}
|
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerAwareTrait.php
vendored
Normal file
41
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerAwareTrait.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?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;
|
||||
|
||||
trigger_deprecation('symfony/dependency-injection', '6.4', '"%s" is deprecated, use dependency injection instead.', ContainerAwareTrait::class);
|
||||
|
||||
/**
|
||||
* ContainerAware trait.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 6.4, use dependency injection instead
|
||||
*/
|
||||
trait ContainerAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface|null
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setContainer(?ContainerInterface $container = null)
|
||||
{
|
||||
if (1 > \func_num_args()) {
|
||||
trigger_deprecation('symfony/dependency-injection', '6.2', 'Calling "%s::%s()" without any arguments is deprecated, pass null explicitly instead.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
1729
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerBuilder.php
vendored
Normal file
1729
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerBuilder.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
72
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerInterface.php
vendored
Normal file
72
plugins/simplesaml/lib/vendor/symfony/dependency-injection/ContainerInterface.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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;
|
||||
|
||||
use Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
|
||||
/**
|
||||
* ContainerInterface is the interface implemented by service container classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface ContainerInterface extends PsrContainerInterface
|
||||
{
|
||||
public const RUNTIME_EXCEPTION_ON_INVALID_REFERENCE = 0;
|
||||
public const EXCEPTION_ON_INVALID_REFERENCE = 1;
|
||||
public const NULL_ON_INVALID_REFERENCE = 2;
|
||||
public const IGNORE_ON_INVALID_REFERENCE = 3;
|
||||
public const IGNORE_ON_UNINITIALIZED_REFERENCE = 4;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $id, ?object $service);
|
||||
|
||||
/**
|
||||
* @template B of self::*_REFERENCE
|
||||
*
|
||||
* @param B $invalidBehavior
|
||||
*
|
||||
* @psalm-return (B is self::EXCEPTION_ON_INVALID_REFERENCE|self::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE ? object : object|null)
|
||||
*
|
||||
* @throws ServiceCircularReferenceException When a circular reference is detected
|
||||
* @throws ServiceNotFoundException When the service is not defined
|
||||
*
|
||||
* @see Reference
|
||||
*/
|
||||
public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE): ?object;
|
||||
|
||||
public function has(string $id): bool;
|
||||
|
||||
/**
|
||||
* Check for whether or not a service has been initialized.
|
||||
*/
|
||||
public function initialized(string $id): bool;
|
||||
|
||||
/**
|
||||
* @return array|bool|string|int|float|\UnitEnum|null
|
||||
*
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*/
|
||||
public function getParameter(string $name);
|
||||
|
||||
public function hasParameter(string $name): bool;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setParameter(string $name, array|bool|string|int|float|\UnitEnum|null $value);
|
||||
}
|
813
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Definition.php
vendored
Normal file
813
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Definition.php
vendored
Normal file
@@ -0,0 +1,813 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Definition represents a service definition.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Definition
|
||||
{
|
||||
private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.';
|
||||
|
||||
private ?string $class = null;
|
||||
private ?string $file = null;
|
||||
private string|array|null $factory = null;
|
||||
private bool $shared = true;
|
||||
private array $deprecation = [];
|
||||
private array $properties = [];
|
||||
private array $calls = [];
|
||||
private array $instanceof = [];
|
||||
private bool $autoconfigured = false;
|
||||
private string|array|null $configurator = null;
|
||||
private array $tags = [];
|
||||
private bool $public = false;
|
||||
private bool $synthetic = false;
|
||||
private bool $abstract = false;
|
||||
private bool $lazy = false;
|
||||
private ?array $decoratedService = null;
|
||||
private bool $autowired = false;
|
||||
private array $changes = [];
|
||||
private array $bindings = [];
|
||||
private array $errors = [];
|
||||
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Used to store the name of the inner id when using service decoration together with autowiring
|
||||
*/
|
||||
public ?string $innerServiceId = null;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Used to store the behavior to follow when using service decoration and the decorated service is invalid
|
||||
*/
|
||||
public ?int $decorationOnInvalid = null;
|
||||
|
||||
public function __construct(?string $class = null, array $arguments = [])
|
||||
{
|
||||
if (null !== $class) {
|
||||
$this->setClass($class);
|
||||
}
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all changes tracked for the Definition object.
|
||||
*/
|
||||
public function getChanges(): array
|
||||
{
|
||||
return $this->changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tracked changes for the Definition object.
|
||||
*
|
||||
* @param array $changes An array of changes for this Definition
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChanges(array $changes): static
|
||||
{
|
||||
$this->changes = $changes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a factory.
|
||||
*
|
||||
* @param string|array|Reference|null $factory A PHP function, reference or an array containing a class/Reference and a method to call
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFactory(string|array|Reference|null $factory): static
|
||||
{
|
||||
$this->changes['factory'] = true;
|
||||
|
||||
if (\is_string($factory) && str_contains($factory, '::')) {
|
||||
$factory = explode('::', $factory, 2);
|
||||
} elseif ($factory instanceof Reference) {
|
||||
$factory = [$factory, '__invoke'];
|
||||
}
|
||||
|
||||
$this->factory = $factory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory.
|
||||
*
|
||||
* @return string|array|null The PHP function or an array containing a class/Reference and a method to call
|
||||
*/
|
||||
public function getFactory(): string|array|null
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service that this service is decorating.
|
||||
*
|
||||
* @param string|null $id The decorated service id, use null to remove decoration
|
||||
* @param string|null $renamedId The new decorated service id
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
|
||||
*/
|
||||
public function setDecoratedService(?string $id, ?string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static
|
||||
{
|
||||
if ($renamedId && $id === $renamedId) {
|
||||
throw new InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
|
||||
}
|
||||
|
||||
$this->changes['decorated_service'] = true;
|
||||
|
||||
if (null === $id) {
|
||||
$this->decoratedService = null;
|
||||
} else {
|
||||
$this->decoratedService = [$id, $renamedId, $priority];
|
||||
|
||||
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
|
||||
$this->decoratedService[] = $invalidBehavior;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service that this service is decorating.
|
||||
*
|
||||
* @return array|null An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
|
||||
*/
|
||||
public function getDecoratedService(): ?array
|
||||
{
|
||||
return $this->decoratedService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service class.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setClass(?string $class): static
|
||||
{
|
||||
$this->changes['class'] = true;
|
||||
|
||||
$this->class = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service class.
|
||||
*/
|
||||
public function getClass(): ?string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments to pass to the service constructor/factory method.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setArguments(array $arguments): static
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the properties to define when creating the service.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperties(array $properties): static
|
||||
{
|
||||
$this->properties = $properties;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the properties to define when creating the service.
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific property.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperty(string $name, mixed $value): static
|
||||
{
|
||||
$this->properties[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addArgument(mixed $argument): static
|
||||
{
|
||||
$this->arguments[] = $argument;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a specific argument.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws OutOfBoundsException When the replaced argument does not exist
|
||||
*/
|
||||
public function replaceArgument(int|string $index, mixed $argument): static
|
||||
{
|
||||
if (0 === \count($this->arguments)) {
|
||||
throw new OutOfBoundsException(sprintf('Cannot replace arguments for class "%s" if none have been configured yet.', $this->class));
|
||||
}
|
||||
|
||||
if (\is_int($index) && ($index < 0 || $index > \count($this->arguments) - 1)) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d] of the arguments of class "%s".', $index, \count($this->arguments) - 1, $this->class));
|
||||
}
|
||||
|
||||
if (!\array_key_exists($index, $this->arguments)) {
|
||||
throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist in class "%s".', $index, $this->class));
|
||||
}
|
||||
|
||||
$this->arguments[$index] = $argument;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific argument.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setArgument(int|string $key, mixed $value): static
|
||||
{
|
||||
$this->arguments[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the arguments to pass to the service constructor/factory method.
|
||||
*/
|
||||
public function getArguments(): array
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* @throws OutOfBoundsException When the argument does not exist
|
||||
*/
|
||||
public function getArgument(int|string $index): mixed
|
||||
{
|
||||
if (!\array_key_exists($index, $this->arguments)) {
|
||||
throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist in class "%s".', $index, $this->class));
|
||||
}
|
||||
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the methods to call after service initialization.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMethodCalls(array $calls = []): static
|
||||
{
|
||||
$this->calls = [];
|
||||
foreach ($calls as $call) {
|
||||
$this->addMethodCall($call[0], $call[1], $call[2] ?? false);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a method to call after service initialization.
|
||||
*
|
||||
* @param string $method The method name to call
|
||||
* @param array $arguments An array of arguments to pass to the method call
|
||||
* @param bool $returnsClone Whether the call returns the service instance or not
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException on empty $method param
|
||||
*/
|
||||
public function addMethodCall(string $method, array $arguments = [], bool $returnsClone = false): static
|
||||
{
|
||||
if (empty($method)) {
|
||||
throw new InvalidArgumentException('Method name cannot be empty.');
|
||||
}
|
||||
$this->calls[] = $returnsClone ? [$method, $arguments, true] : [$method, $arguments];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a method to call after service initialization.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeMethodCall(string $method): static
|
||||
{
|
||||
foreach ($this->calls as $i => $call) {
|
||||
if ($call[0] === $method) {
|
||||
unset($this->calls[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current definition has a given method to call after service initialization.
|
||||
*/
|
||||
public function hasMethodCall(string $method): bool
|
||||
{
|
||||
foreach ($this->calls as $call) {
|
||||
if ($call[0] === $method) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the methods to call after service initialization.
|
||||
*/
|
||||
public function getMethodCalls(): array
|
||||
{
|
||||
return $this->calls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
|
||||
*
|
||||
* @param ChildDefinition[] $instanceof
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setInstanceofConditionals(array $instanceof): static
|
||||
{
|
||||
$this->instanceof = $instanceof;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
|
||||
*
|
||||
* @return ChildDefinition[]
|
||||
*/
|
||||
public function getInstanceofConditionals(): array
|
||||
{
|
||||
return $this->instanceof;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not instanceof conditionals should be prepended with a global set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAutoconfigured(bool $autoconfigured): static
|
||||
{
|
||||
$this->changes['autoconfigured'] = true;
|
||||
|
||||
$this->autoconfigured = $autoconfigured;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isAutoconfigured(): bool
|
||||
{
|
||||
return $this->autoconfigured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tags for this definition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTags(array $tags): static
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*/
|
||||
public function getTags(): array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tag by name.
|
||||
*/
|
||||
public function getTag(string $name): array
|
||||
{
|
||||
return $this->tags[$name] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tag for this definition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTag(string $name, array $attributes = []): static
|
||||
{
|
||||
$this->tags[$name][] = $attributes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition has a tag with the given name.
|
||||
*/
|
||||
public function hasTag(string $name): bool
|
||||
{
|
||||
return isset($this->tags[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all tags for a given name.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function clearTag(string $name): static
|
||||
{
|
||||
unset($this->tags[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the tags for this definition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function clearTags(): static
|
||||
{
|
||||
$this->tags = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a file to require before creating the service.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFile(?string $file): static
|
||||
{
|
||||
$this->changes['file'] = true;
|
||||
|
||||
$this->file = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file to require before creating the service.
|
||||
*/
|
||||
public function getFile(): ?string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the service must be shared or not.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setShared(bool $shared): static
|
||||
{
|
||||
$this->changes['shared'] = true;
|
||||
|
||||
$this->shared = $shared;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is shared.
|
||||
*/
|
||||
public function isShared(): bool
|
||||
{
|
||||
return $this->shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of this service.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPublic(bool $boolean): static
|
||||
{
|
||||
$this->changes['public'] = true;
|
||||
|
||||
$this->public = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is public facing.
|
||||
*/
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is private.
|
||||
*/
|
||||
public function isPrivate(): bool
|
||||
{
|
||||
return !$this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lazy flag of this service.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLazy(bool $lazy): static
|
||||
{
|
||||
$this->changes['lazy'] = true;
|
||||
|
||||
$this->lazy = $lazy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is lazy.
|
||||
*/
|
||||
public function isLazy(): bool
|
||||
{
|
||||
return $this->lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSynthetic(bool $boolean): static
|
||||
{
|
||||
$this->synthetic = $boolean;
|
||||
|
||||
if (!isset($this->changes['public'])) {
|
||||
$this->setPublic(true);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*/
|
||||
public function isSynthetic(): bool
|
||||
{
|
||||
return $this->synthetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAbstract(bool $boolean): static
|
||||
{
|
||||
$this->abstract = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*/
|
||||
public function isAbstract(): bool
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is deprecated, that means it should not be called
|
||||
* anymore.
|
||||
*
|
||||
* @param string $package The name of the composer package that is triggering the deprecation
|
||||
* @param string $version The version of the package that introduced the deprecation
|
||||
* @param string $message The deprecation message to use
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException when the message template is invalid
|
||||
*/
|
||||
public function setDeprecated(string $package, string $version, string $message): static
|
||||
{
|
||||
if ('' !== $message) {
|
||||
if (preg_match('#[\r\n]|\*/#', $message)) {
|
||||
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
|
||||
}
|
||||
|
||||
if (!str_contains($message, '%service_id%')) {
|
||||
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->changes['deprecated'] = true;
|
||||
$this->deprecation = ['package' => $package, 'version' => $version, 'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is deprecated, that means it should not be called
|
||||
* anymore.
|
||||
*/
|
||||
public function isDeprecated(): bool
|
||||
{
|
||||
return (bool) $this->deprecation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id Service id relying on this definition
|
||||
*/
|
||||
public function getDeprecation(string $id): array
|
||||
{
|
||||
return [
|
||||
'package' => $this->deprecation['package'],
|
||||
'version' => $this->deprecation['version'],
|
||||
'message' => str_replace('%service_id%', $id, $this->deprecation['message']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configurator to call after the service is fully initialized.
|
||||
*
|
||||
* @param string|array|Reference|null $configurator A PHP function, reference or an array containing a class/Reference and a method to call
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfigurator(string|array|Reference|null $configurator): static
|
||||
{
|
||||
$this->changes['configurator'] = true;
|
||||
|
||||
if (\is_string($configurator) && str_contains($configurator, '::')) {
|
||||
$configurator = explode('::', $configurator, 2);
|
||||
} elseif ($configurator instanceof Reference) {
|
||||
$configurator = [$configurator, '__invoke'];
|
||||
}
|
||||
|
||||
$this->configurator = $configurator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configurator to call after the service is fully initialized.
|
||||
*/
|
||||
public function getConfigurator(): string|array|null
|
||||
{
|
||||
return $this->configurator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the definition autowired?
|
||||
*/
|
||||
public function isAutowired(): bool
|
||||
{
|
||||
return $this->autowired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables autowiring.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAutowired(bool $autowired): static
|
||||
{
|
||||
$this->changes['autowired'] = true;
|
||||
|
||||
$this->autowired = $autowired;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets bindings.
|
||||
*
|
||||
* @return BoundArgument[]
|
||||
*/
|
||||
public function getBindings(): array
|
||||
{
|
||||
return $this->bindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bindings.
|
||||
*
|
||||
* Bindings map $named or FQCN arguments to values that should be
|
||||
* injected in the matching parameters (of the constructor, of methods
|
||||
* called and of controller actions).
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBindings(array $bindings): static
|
||||
{
|
||||
foreach ($bindings as $key => $binding) {
|
||||
if (0 < strpos($key, '$') && $key !== $k = preg_replace('/[ \t]*\$/', ' $', $key)) {
|
||||
unset($bindings[$key]);
|
||||
$bindings[$key = $k] = $binding;
|
||||
}
|
||||
if (!$binding instanceof BoundArgument) {
|
||||
$bindings[$key] = new BoundArgument($binding);
|
||||
}
|
||||
}
|
||||
|
||||
$this->bindings = $bindings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error that occurred when building this Definition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addError(string|\Closure|self $error): static
|
||||
{
|
||||
if ($error instanceof self) {
|
||||
$this->errors = array_merge($this->errors, $error->errors);
|
||||
} else {
|
||||
$this->errors[] = $error;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any errors that occurred while building this Definition.
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
foreach ($this->errors as $i => $error) {
|
||||
if ($error instanceof \Closure) {
|
||||
$this->errors[$i] = (string) $error();
|
||||
} elseif (!\is_string($error)) {
|
||||
$this->errors[$i] = (string) $error;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
return (bool) $this->errors;
|
||||
}
|
||||
}
|
29
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/Dumper.php
vendored
Normal file
29
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/Dumper.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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Dumper is the abstract class for all built-in dumpers.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Dumper implements DumperInterface
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/DumperInterface.php
vendored
Normal file
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/DumperInterface.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\Dumper;
|
||||
|
||||
/**
|
||||
* DumperInterface is the interface implemented by service container dumper classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface DumperInterface
|
||||
{
|
||||
/**
|
||||
* Dumps the service container.
|
||||
*/
|
||||
public function dump(array $options = []): string|array;
|
||||
}
|
249
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php
vendored
Normal file
249
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* GraphvizDumper dumps a service container as a graphviz file.
|
||||
*
|
||||
* You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
|
||||
*
|
||||
* dot -Tpng container.dot > foo.png
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class GraphvizDumper extends Dumper
|
||||
{
|
||||
private array $nodes;
|
||||
private array $edges;
|
||||
// All values should be strings
|
||||
private array $options = [
|
||||
'graph' => ['ratio' => 'compress'],
|
||||
'node' => ['fontsize' => '11', 'fontname' => 'Arial', 'shape' => 'record'],
|
||||
'edge' => ['fontsize' => '9', 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => '0.5'],
|
||||
'node.instance' => ['fillcolor' => '#9999ff', 'style' => 'filled'],
|
||||
'node.definition' => ['fillcolor' => '#eeeeee'],
|
||||
'node.missing' => ['fillcolor' => '#ff9999', 'style' => 'filled'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Dumps the service container as a graphviz graph.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * graph: The default options for the whole graph
|
||||
* * node: The default options for nodes
|
||||
* * edge: The default options for edges
|
||||
* * node.instance: The default options for services that are defined directly by object instances
|
||||
* * node.definition: The default options for services that are defined via service definition instances
|
||||
* * node.missing: The default options for missing services
|
||||
*/
|
||||
public function dump(array $options = []): string
|
||||
{
|
||||
foreach (['graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing'] as $key) {
|
||||
if (isset($options[$key])) {
|
||||
$this->options[$key] = array_merge($this->options[$key], $options[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->nodes = $this->findNodes();
|
||||
|
||||
$this->edges = [];
|
||||
foreach ($this->container->getDefinitions() as $id => $definition) {
|
||||
$this->edges[$id] = array_merge(
|
||||
$this->findEdges($id, $definition->getArguments(), true, ''),
|
||||
$this->findEdges($id, $definition->getProperties(), false, '')
|
||||
);
|
||||
|
||||
foreach ($definition->getMethodCalls() as $call) {
|
||||
$this->edges[$id] = array_merge(
|
||||
$this->edges[$id],
|
||||
$this->findEdges($id, $call[1], false, $call[0].'()')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->container->resolveEnvPlaceholders($this->startDot().$this->addNodes().$this->addEdges().$this->endDot(), '__ENV_%s__');
|
||||
}
|
||||
|
||||
private function addNodes(): string
|
||||
{
|
||||
$code = '';
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
$aliases = $this->getAliases($id);
|
||||
|
||||
$code .= sprintf(" node_%s [label=\"%s\\n%s\\n\", shape=%s%s];\n", $this->dotize($id), $id.($aliases ? ' ('.implode(', ', $aliases).')' : ''), $node['class'], $this->options['node']['shape'], $this->addAttributes($node['attributes']));
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private function addEdges(): string
|
||||
{
|
||||
$code = '';
|
||||
foreach ($this->edges as $id => $edges) {
|
||||
foreach ($edges as $edge) {
|
||||
$code .= sprintf(" node_%s -> node_%s [label=\"%s\" style=\"%s\"%s];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed', $edge['lazy'] ? ' color="#9999ff"' : '');
|
||||
}
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all edges belonging to a specific service id.
|
||||
*/
|
||||
private function findEdges(string $id, array $arguments, bool $required, string $name, bool $lazy = false): array
|
||||
{
|
||||
$edges = [];
|
||||
foreach ($arguments as $argument) {
|
||||
if ($argument instanceof Parameter) {
|
||||
$argument = $this->container->hasParameter($argument) ? $this->container->getParameter($argument) : null;
|
||||
} elseif (\is_string($argument) && preg_match('/^%([^%]+)%$/', $argument, $match)) {
|
||||
$argument = $this->container->hasParameter($match[1]) ? $this->container->getParameter($match[1]) : null;
|
||||
}
|
||||
|
||||
if ($argument instanceof Reference) {
|
||||
$lazyEdge = $lazy;
|
||||
|
||||
if (!$this->container->has((string) $argument)) {
|
||||
$this->nodes[(string) $argument] = ['name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']];
|
||||
} elseif ('service_container' !== (string) $argument) {
|
||||
$lazyEdge = $lazy || $this->container->getDefinition((string) $argument)->isLazy();
|
||||
}
|
||||
|
||||
$edges[] = [['name' => $name, 'required' => $required, 'to' => $argument, 'lazy' => $lazyEdge]];
|
||||
} elseif ($argument instanceof ArgumentInterface) {
|
||||
$edges[] = $this->findEdges($id, $argument->getValues(), $required, $name, true);
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$edges[] = $this->findEdges($id, $argument->getArguments(), $required, '');
|
||||
$edges[] = $this->findEdges($id, $argument->getProperties(), false, '');
|
||||
|
||||
foreach ($argument->getMethodCalls() as $call) {
|
||||
$edges[] = $this->findEdges($id, $call[1], false, $call[0].'()');
|
||||
}
|
||||
} elseif (\is_array($argument)) {
|
||||
$edges[] = $this->findEdges($id, $argument, $required, $name, $lazy);
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge([], ...$edges);
|
||||
}
|
||||
|
||||
private function findNodes(): array
|
||||
{
|
||||
$nodes = [];
|
||||
|
||||
$container = $this->cloneContainer();
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$class = $definition->getClass();
|
||||
|
||||
if (str_starts_with($class, '\\')) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
try {
|
||||
$class = $this->container->getParameterBag()->resolveValue($class);
|
||||
} catch (ParameterNotFoundException) {
|
||||
}
|
||||
|
||||
$nodes[$id] = ['class' => str_replace('\\', '\\\\', $class), 'attributes' => array_merge($this->options['node.definition'], ['style' => $definition->isShared() ? 'filled' : 'dotted'])];
|
||||
$container->setDefinition($id, new Definition('stdClass'));
|
||||
}
|
||||
|
||||
foreach ($container->getServiceIds() as $id) {
|
||||
if (\array_key_exists($id, $container->getAliases())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition($id)) {
|
||||
$nodes[$id] = ['class' => str_replace('\\', '\\\\', $container->get($id)::class), 'attributes' => $this->options['node.instance']];
|
||||
}
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
private function cloneContainer(): ContainerBuilder
|
||||
{
|
||||
$parameterBag = new ParameterBag($this->container->getParameterBag()->all());
|
||||
|
||||
$container = new ContainerBuilder($parameterBag);
|
||||
$container->setDefinitions($this->container->getDefinitions());
|
||||
$container->setAliases($this->container->getAliases());
|
||||
$container->setResources($this->container->getResources());
|
||||
foreach ($this->container->getExtensions() as $extension) {
|
||||
$container->registerExtension($extension);
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
private function startDot(): string
|
||||
{
|
||||
return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n",
|
||||
$this->addOptions($this->options['graph']),
|
||||
$this->addOptions($this->options['node']),
|
||||
$this->addOptions($this->options['edge'])
|
||||
);
|
||||
}
|
||||
|
||||
private function endDot(): string
|
||||
{
|
||||
return "}\n";
|
||||
}
|
||||
|
||||
private function addAttributes(array $attributes): string
|
||||
{
|
||||
$code = [];
|
||||
foreach ($attributes as $k => $v) {
|
||||
$code[] = sprintf('%s="%s"', $k, $v);
|
||||
}
|
||||
|
||||
return $code ? ', '.implode(', ', $code) : '';
|
||||
}
|
||||
|
||||
private function addOptions(array $options): string
|
||||
{
|
||||
$code = [];
|
||||
foreach ($options as $k => $v) {
|
||||
$code[] = sprintf('%s="%s"', $k, $v);
|
||||
}
|
||||
|
||||
return implode(' ', $code);
|
||||
}
|
||||
|
||||
private function dotize(string $id): string
|
||||
{
|
||||
return preg_replace('/\W/i', '_', $id);
|
||||
}
|
||||
|
||||
private function getAliases(string $id): array
|
||||
{
|
||||
$aliases = [];
|
||||
foreach ($this->container->getAliases() as $alias => $origin) {
|
||||
if ($id == $origin) {
|
||||
$aliases[] = $alias;
|
||||
}
|
||||
}
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
}
|
2406
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/PhpDumper.php
vendored
Normal file
2406
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/PhpDumper.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
129
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/Preloader.php
vendored
Normal file
129
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/Preloader.php
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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\Dumper;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class Preloader
|
||||
{
|
||||
public static function append(string $file, array $list): void
|
||||
{
|
||||
if (!file_exists($file)) {
|
||||
throw new \LogicException(sprintf('File "%s" does not exist.', $file));
|
||||
}
|
||||
|
||||
$cacheDir = \dirname($file);
|
||||
$classes = [];
|
||||
|
||||
foreach ($list as $item) {
|
||||
if (str_starts_with($item, $cacheDir)) {
|
||||
file_put_contents($file, sprintf("require_once __DIR__.%s;\n", var_export(strtr(substr($item, \strlen($cacheDir)), \DIRECTORY_SEPARATOR, '/'), true)), \FILE_APPEND);
|
||||
continue;
|
||||
}
|
||||
|
||||
$classes[] = sprintf("\$classes[] = %s;\n", var_export($item, true));
|
||||
}
|
||||
|
||||
file_put_contents($file, sprintf("\n\$classes = [];\n%s\$preloaded = Preloader::preload(\$classes, \$preloaded);\n", implode('', $classes)), \FILE_APPEND);
|
||||
}
|
||||
|
||||
public static function preload(array $classes, array $preloaded = []): array
|
||||
{
|
||||
set_error_handler(function ($t, $m, $f, $l) {
|
||||
if (error_reporting() & $t) {
|
||||
if (__FILE__ !== $f) {
|
||||
throw new \ErrorException($m, 0, $t, $f, $l);
|
||||
}
|
||||
|
||||
throw new \ReflectionException($m);
|
||||
}
|
||||
});
|
||||
|
||||
$prev = [];
|
||||
|
||||
try {
|
||||
while ($prev !== $classes) {
|
||||
$prev = $classes;
|
||||
foreach ($classes as $c) {
|
||||
if (!isset($preloaded[$c])) {
|
||||
self::doPreload($c, $preloaded);
|
||||
}
|
||||
}
|
||||
$classes = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
|
||||
}
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
return $preloaded;
|
||||
}
|
||||
|
||||
private static function doPreload(string $class, array &$preloaded): void
|
||||
{
|
||||
if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preloaded[$class] = true;
|
||||
|
||||
try {
|
||||
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = new \ReflectionClass($class);
|
||||
|
||||
if ($r->isInternal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r->getConstants();
|
||||
$r->getDefaultProperties();
|
||||
|
||||
foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) {
|
||||
self::preloadType($p->getType(), $preloaded);
|
||||
}
|
||||
|
||||
foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) {
|
||||
foreach ($m->getParameters() as $p) {
|
||||
if ($p->isDefaultValueAvailable() && $p->isDefaultValueConstant()) {
|
||||
$c = $p->getDefaultValueConstantName();
|
||||
|
||||
if ($i = strpos($c, '::')) {
|
||||
self::doPreload(substr($c, 0, $i), $preloaded);
|
||||
}
|
||||
}
|
||||
|
||||
self::preloadType($p->getType(), $preloaded);
|
||||
}
|
||||
|
||||
self::preloadType($m->getReturnType(), $preloaded);
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// ignore missing classes
|
||||
}
|
||||
}
|
||||
|
||||
private static function preloadType(?\ReflectionType $t, array &$preloaded): void
|
||||
{
|
||||
if (!$t) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (($t instanceof \ReflectionUnionType || $t instanceof \ReflectionIntersectionType) ? $t->getTypes() : [$t] as $t) {
|
||||
if (!$t->isBuiltin()) {
|
||||
self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
432
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/XmlDumper.php
vendored
Normal file
432
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/XmlDumper.php
vendored
Normal file
@@ -0,0 +1,432 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
/**
|
||||
* XmlDumper dumps a service container as an XML string.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class XmlDumper extends Dumper
|
||||
{
|
||||
private \DOMDocument $document;
|
||||
|
||||
/**
|
||||
* Dumps the service container as an XML string.
|
||||
*/
|
||||
public function dump(array $options = []): string
|
||||
{
|
||||
$this->document = new \DOMDocument('1.0', 'utf-8');
|
||||
$this->document->formatOutput = true;
|
||||
|
||||
$container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container');
|
||||
$container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd');
|
||||
|
||||
$this->addParameters($container);
|
||||
$this->addServices($container);
|
||||
|
||||
$this->document->appendChild($container);
|
||||
$xml = $this->document->saveXML();
|
||||
unset($this->document);
|
||||
|
||||
return $this->container->resolveEnvPlaceholders($xml);
|
||||
}
|
||||
|
||||
private function addParameters(\DOMElement $parent): void
|
||||
{
|
||||
$data = $this->container->getParameterBag()->all();
|
||||
if (!$data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->container->isCompiled()) {
|
||||
$data = $this->escape($data);
|
||||
}
|
||||
|
||||
$parameters = $this->document->createElement('parameters');
|
||||
$parent->appendChild($parameters);
|
||||
$this->convertParameters($data, 'parameter', $parameters);
|
||||
}
|
||||
|
||||
private function addMethodCalls(array $methodcalls, \DOMElement $parent): void
|
||||
{
|
||||
foreach ($methodcalls as $methodcall) {
|
||||
$call = $this->document->createElement('call');
|
||||
$call->setAttribute('method', $methodcall[0]);
|
||||
if (\count($methodcall[1])) {
|
||||
$this->convertParameters($methodcall[1], 'argument', $call);
|
||||
}
|
||||
if ($methodcall[2] ?? false) {
|
||||
$call->setAttribute('returns-clone', 'true');
|
||||
}
|
||||
$parent->appendChild($call);
|
||||
}
|
||||
}
|
||||
|
||||
private function addService(Definition $definition, ?string $id, \DOMElement $parent): void
|
||||
{
|
||||
$service = $this->document->createElement('service');
|
||||
if (null !== $id) {
|
||||
$service->setAttribute('id', $id);
|
||||
}
|
||||
if ($class = $definition->getClass()) {
|
||||
if (str_starts_with($class, '\\')) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
$service->setAttribute('class', $class);
|
||||
}
|
||||
if (!$definition->isShared()) {
|
||||
$service->setAttribute('shared', 'false');
|
||||
}
|
||||
if ($definition->isPublic()) {
|
||||
$service->setAttribute('public', 'true');
|
||||
}
|
||||
if ($definition->isSynthetic()) {
|
||||
$service->setAttribute('synthetic', 'true');
|
||||
}
|
||||
if ($definition->isLazy()) {
|
||||
$service->setAttribute('lazy', 'true');
|
||||
}
|
||||
if (null !== $decoratedService = $definition->getDecoratedService()) {
|
||||
[$decorated, $renamedId, $priority] = $decoratedService;
|
||||
$service->setAttribute('decorates', $decorated);
|
||||
|
||||
$decorationOnInvalid = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
if (\in_array($decorationOnInvalid, [ContainerInterface::IGNORE_ON_INVALID_REFERENCE, ContainerInterface::NULL_ON_INVALID_REFERENCE], true)) {
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE === $decorationOnInvalid ? 'null' : 'ignore';
|
||||
$service->setAttribute('decoration-on-invalid', $invalidBehavior);
|
||||
}
|
||||
if (null !== $renamedId) {
|
||||
$service->setAttribute('decoration-inner-name', $renamedId);
|
||||
}
|
||||
if (0 !== $priority) {
|
||||
$service->setAttribute('decoration-priority', $priority);
|
||||
}
|
||||
}
|
||||
|
||||
$tags = $definition->getTags();
|
||||
$tags['container.error'] = array_map(fn ($e) => ['message' => $e], $definition->getErrors());
|
||||
foreach ($tags as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
$tag = $this->document->createElement('tag');
|
||||
|
||||
// Check if we have recursive attributes
|
||||
if (array_filter($attributes, \is_array(...))) {
|
||||
$tag->setAttribute('name', $name);
|
||||
$this->addTagRecursiveAttributes($tag, $attributes);
|
||||
} else {
|
||||
if (!\array_key_exists('name', $attributes)) {
|
||||
$tag->setAttribute('name', $name);
|
||||
} else {
|
||||
$tag->appendChild($this->document->createTextNode($name));
|
||||
}
|
||||
foreach ($attributes as $key => $value) {
|
||||
$tag->setAttribute($key, $value ?? '');
|
||||
}
|
||||
}
|
||||
$service->appendChild($tag);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$file = $this->document->createElement('file');
|
||||
$file->appendChild($this->document->createTextNode($definition->getFile()));
|
||||
$service->appendChild($file);
|
||||
}
|
||||
|
||||
if ($parameters = $definition->getArguments()) {
|
||||
$this->convertParameters($parameters, 'argument', $service);
|
||||
}
|
||||
|
||||
if ($parameters = $definition->getProperties()) {
|
||||
$this->convertParameters($parameters, 'property', $service, 'name');
|
||||
}
|
||||
|
||||
$this->addMethodCalls($definition->getMethodCalls(), $service);
|
||||
|
||||
if ($callable = $definition->getFactory()) {
|
||||
if (\is_array($callable) && ['Closure', 'fromCallable'] !== $callable && $definition->getClass() === $callable[0]) {
|
||||
$service->setAttribute('constructor', $callable[1]);
|
||||
} else {
|
||||
$factory = $this->document->createElement('factory');
|
||||
|
||||
if (\is_array($callable) && $callable[0] instanceof Definition) {
|
||||
$this->addService($callable[0], null, $factory);
|
||||
$factory->setAttribute('method', $callable[1]);
|
||||
} elseif (\is_array($callable)) {
|
||||
if (null !== $callable[0]) {
|
||||
$factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
|
||||
}
|
||||
$factory->setAttribute('method', $callable[1]);
|
||||
} else {
|
||||
$factory->setAttribute('function', $callable);
|
||||
}
|
||||
$service->appendChild($factory);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->isDeprecated()) {
|
||||
$deprecation = $definition->getDeprecation('%service_id%');
|
||||
$deprecated = $this->document->createElement('deprecated');
|
||||
$deprecated->appendChild($this->document->createTextNode($definition->getDeprecation('%service_id%')['message']));
|
||||
$deprecated->setAttribute('package', $deprecation['package']);
|
||||
$deprecated->setAttribute('version', $deprecation['version']);
|
||||
|
||||
$service->appendChild($deprecated);
|
||||
}
|
||||
|
||||
if ($definition->isAutowired()) {
|
||||
$service->setAttribute('autowire', 'true');
|
||||
}
|
||||
|
||||
if ($definition->isAutoconfigured()) {
|
||||
$service->setAttribute('autoconfigure', 'true');
|
||||
}
|
||||
|
||||
if ($definition->isAbstract()) {
|
||||
$service->setAttribute('abstract', 'true');
|
||||
}
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
$configurator = $this->document->createElement('configurator');
|
||||
|
||||
if (\is_array($callable) && $callable[0] instanceof Definition) {
|
||||
$this->addService($callable[0], null, $configurator);
|
||||
$configurator->setAttribute('method', $callable[1]);
|
||||
} elseif (\is_array($callable)) {
|
||||
$configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
|
||||
$configurator->setAttribute('method', $callable[1]);
|
||||
} else {
|
||||
$configurator->setAttribute('function', $callable);
|
||||
}
|
||||
$service->appendChild($configurator);
|
||||
}
|
||||
|
||||
$parent->appendChild($service);
|
||||
}
|
||||
|
||||
private function addServiceAlias(string $alias, Alias $id, \DOMElement $parent): void
|
||||
{
|
||||
$service = $this->document->createElement('service');
|
||||
$service->setAttribute('id', $alias);
|
||||
$service->setAttribute('alias', $id);
|
||||
if ($id->isPublic()) {
|
||||
$service->setAttribute('public', 'true');
|
||||
}
|
||||
|
||||
if ($id->isDeprecated()) {
|
||||
$deprecation = $id->getDeprecation('%alias_id%');
|
||||
$deprecated = $this->document->createElement('deprecated');
|
||||
$deprecated->appendChild($this->document->createTextNode($deprecation['message']));
|
||||
$deprecated->setAttribute('package', $deprecation['package']);
|
||||
$deprecated->setAttribute('version', $deprecation['version']);
|
||||
|
||||
$service->appendChild($deprecated);
|
||||
}
|
||||
|
||||
$parent->appendChild($service);
|
||||
}
|
||||
|
||||
private function addServices(\DOMElement $parent): void
|
||||
{
|
||||
$definitions = $this->container->getDefinitions();
|
||||
if (!$definitions) {
|
||||
return;
|
||||
}
|
||||
|
||||
$services = $this->document->createElement('services');
|
||||
foreach ($definitions as $id => $definition) {
|
||||
$this->addService($definition, $id, $services);
|
||||
}
|
||||
|
||||
$aliases = $this->container->getAliases();
|
||||
foreach ($aliases as $alias => $id) {
|
||||
while (isset($aliases[(string) $id])) {
|
||||
$id = $aliases[(string) $id];
|
||||
}
|
||||
$this->addServiceAlias($alias, $id, $services);
|
||||
}
|
||||
$parent->appendChild($services);
|
||||
}
|
||||
|
||||
private function addTagRecursiveAttributes(\DOMElement $parent, array $attributes): void
|
||||
{
|
||||
foreach ($attributes as $name => $value) {
|
||||
$attribute = $this->document->createElement('attribute');
|
||||
$attribute->setAttribute('name', $name);
|
||||
|
||||
if (\is_array($value)) {
|
||||
$this->addTagRecursiveAttributes($attribute, $value);
|
||||
} else {
|
||||
$attribute->appendChild($this->document->createTextNode($value));
|
||||
}
|
||||
|
||||
$parent->appendChild($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
private function convertParameters(array $parameters, string $type, \DOMElement $parent, string $keyAttribute = 'key'): void
|
||||
{
|
||||
$withKeys = !array_is_list($parameters);
|
||||
foreach ($parameters as $key => $value) {
|
||||
$element = $this->document->createElement($type);
|
||||
if ($withKeys) {
|
||||
$element->setAttribute($keyAttribute, $key);
|
||||
}
|
||||
|
||||
if (\is_array($tag = $value)) {
|
||||
$element->setAttribute('type', 'collection');
|
||||
$this->convertParameters($value, $type, $element, 'key');
|
||||
} elseif ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) {
|
||||
$element->setAttribute('type', $value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator');
|
||||
$element->setAttribute('tag', $tag->getTag());
|
||||
|
||||
if (null !== $tag->getIndexAttribute()) {
|
||||
$element->setAttribute('index-by', $tag->getIndexAttribute());
|
||||
|
||||
if (null !== $tag->getDefaultIndexMethod()) {
|
||||
$element->setAttribute('default-index-method', $tag->getDefaultIndexMethod());
|
||||
}
|
||||
if (null !== $tag->getDefaultPriorityMethod()) {
|
||||
$element->setAttribute('default-priority-method', $tag->getDefaultPriorityMethod());
|
||||
}
|
||||
}
|
||||
if ($excludes = $tag->getExclude()) {
|
||||
if (1 === \count($excludes)) {
|
||||
$element->setAttribute('exclude', $excludes[0]);
|
||||
} else {
|
||||
foreach ($excludes as $exclude) {
|
||||
$element->appendChild($this->document->createElement('exclude', $exclude));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$tag->excludeSelf()) {
|
||||
$element->setAttribute('exclude-self', 'false');
|
||||
}
|
||||
} elseif ($value instanceof IteratorArgument) {
|
||||
$element->setAttribute('type', 'iterator');
|
||||
$this->convertParameters($value->getValues(), $type, $element, 'key');
|
||||
} elseif ($value instanceof ServiceLocatorArgument) {
|
||||
$element->setAttribute('type', 'service_locator');
|
||||
$this->convertParameters($value->getValues(), $type, $element, 'key');
|
||||
} elseif ($value instanceof ServiceClosureArgument && !$value->getValues()[0] instanceof Reference) {
|
||||
$element->setAttribute('type', 'service_closure');
|
||||
$this->convertParameters($value->getValues(), $type, $element, 'key');
|
||||
} elseif ($value instanceof Reference || $value instanceof ServiceClosureArgument) {
|
||||
$element->setAttribute('type', 'service');
|
||||
if ($value instanceof ServiceClosureArgument) {
|
||||
$element->setAttribute('type', 'service_closure');
|
||||
$value = $value->getValues()[0];
|
||||
}
|
||||
$element->setAttribute('id', (string) $value);
|
||||
$behavior = $value->getInvalidBehavior();
|
||||
if (ContainerInterface::NULL_ON_INVALID_REFERENCE == $behavior) {
|
||||
$element->setAttribute('on-invalid', 'null');
|
||||
} elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE == $behavior) {
|
||||
$element->setAttribute('on-invalid', 'ignore');
|
||||
} elseif (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE == $behavior) {
|
||||
$element->setAttribute('on-invalid', 'ignore_uninitialized');
|
||||
}
|
||||
} elseif ($value instanceof Definition) {
|
||||
$element->setAttribute('type', 'service');
|
||||
$this->addService($value, null, $element);
|
||||
} elseif ($value instanceof Expression) {
|
||||
$element->setAttribute('type', 'expression');
|
||||
$text = $this->document->createTextNode(self::phpToXml((string) $value));
|
||||
$element->appendChild($text);
|
||||
} elseif (\is_string($value) && !preg_match('/^[^\x00-\x08\x0B\x0C\x0E-\x1F\x7F]*+$/u', $value)) {
|
||||
$element->setAttribute('type', 'binary');
|
||||
$text = $this->document->createTextNode(self::phpToXml(base64_encode($value)));
|
||||
$element->appendChild($text);
|
||||
} elseif ($value instanceof \UnitEnum) {
|
||||
$element->setAttribute('type', 'constant');
|
||||
$element->appendChild($this->document->createTextNode(self::phpToXml($value)));
|
||||
} elseif ($value instanceof AbstractArgument) {
|
||||
$element->setAttribute('type', 'abstract');
|
||||
$text = $this->document->createTextNode(self::phpToXml($value->getText()));
|
||||
$element->appendChild($text);
|
||||
} else {
|
||||
if (\in_array($value, ['null', 'true', 'false'], true)) {
|
||||
$element->setAttribute('type', 'string');
|
||||
}
|
||||
|
||||
if (\is_string($value) && (is_numeric($value) || preg_match('/^0b[01]*$/', $value) || preg_match('/^0x[0-9a-f]++$/i', $value))) {
|
||||
$element->setAttribute('type', 'string');
|
||||
}
|
||||
|
||||
$text = $this->document->createTextNode(self::phpToXml($value));
|
||||
$element->appendChild($text);
|
||||
}
|
||||
$parent->appendChild($element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes arguments.
|
||||
*/
|
||||
private function escape(array $arguments): array
|
||||
{
|
||||
$args = [];
|
||||
foreach ($arguments as $k => $v) {
|
||||
if (\is_array($v)) {
|
||||
$args[$k] = $this->escape($v);
|
||||
} elseif (\is_string($v)) {
|
||||
$args[$k] = str_replace('%', '%%', $v);
|
||||
} else {
|
||||
$args[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts php types to xml types.
|
||||
*
|
||||
* @throws RuntimeException When trying to dump object or resource
|
||||
*/
|
||||
public static function phpToXml(mixed $value): string
|
||||
{
|
||||
switch (true) {
|
||||
case null === $value:
|
||||
return 'null';
|
||||
case true === $value:
|
||||
return 'true';
|
||||
case false === $value:
|
||||
return 'false';
|
||||
case $value instanceof Parameter:
|
||||
return '%'.$value.'%';
|
||||
case $value instanceof \UnitEnum:
|
||||
return sprintf('%s::%s', $value::class, $value->name);
|
||||
case \is_object($value) || \is_resource($value):
|
||||
throw new RuntimeException(sprintf('Unable to dump a service container if a parameter is an object or a resource, got "%s".', get_debug_type($value)));
|
||||
default:
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
380
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/YamlDumper.php
vendored
Normal file
380
plugins/simplesaml/lib/vendor/symfony/dependency-injection/Dumper/YamlDumper.php
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\Yaml\Dumper as YmlDumper;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
use Symfony\Component\Yaml\Tag\TaggedValue;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* YamlDumper dumps a service container as a YAML string.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class YamlDumper extends Dumper
|
||||
{
|
||||
private YmlDumper $dumper;
|
||||
|
||||
/**
|
||||
* Dumps the service container as an YAML string.
|
||||
*/
|
||||
public function dump(array $options = []): string
|
||||
{
|
||||
if (!class_exists(YmlDumper::class)) {
|
||||
throw new LogicException('Unable to dump the container as the Symfony Yaml Component is not installed. Try running "composer require symfony/yaml".');
|
||||
}
|
||||
|
||||
$this->dumper ??= new YmlDumper();
|
||||
|
||||
return $this->container->resolveEnvPlaceholders($this->addParameters()."\n".$this->addServices());
|
||||
}
|
||||
|
||||
private function addService(string $id, Definition $definition): string
|
||||
{
|
||||
$code = " $id:\n";
|
||||
if ($class = $definition->getClass()) {
|
||||
if (str_starts_with($class, '\\')) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
$code .= sprintf(" class: %s\n", $this->dumper->dump($class));
|
||||
}
|
||||
|
||||
if (!$definition->isPrivate()) {
|
||||
$code .= sprintf(" public: %s\n", $definition->isPublic() ? 'true' : 'false');
|
||||
}
|
||||
|
||||
$tagsCode = '';
|
||||
$tags = $definition->getTags();
|
||||
$tags['container.error'] = array_map(fn ($e) => ['message' => $e], $definition->getErrors());
|
||||
foreach ($tags as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
$att = [];
|
||||
foreach ($attributes as $key => $value) {
|
||||
$att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
|
||||
}
|
||||
$att = $att ? ': { '.implode(', ', $att).' }' : '';
|
||||
|
||||
$tagsCode .= sprintf(" - %s%s\n", $this->dumper->dump($name), $att);
|
||||
}
|
||||
}
|
||||
if ($tagsCode) {
|
||||
$code .= " tags:\n".$tagsCode;
|
||||
}
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile()));
|
||||
}
|
||||
|
||||
if ($definition->isSynthetic()) {
|
||||
$code .= " synthetic: true\n";
|
||||
}
|
||||
|
||||
if ($definition->isDeprecated()) {
|
||||
$code .= " deprecated:\n";
|
||||
foreach ($definition->getDeprecation('%service_id%') as $key => $value) {
|
||||
if ('' !== $value) {
|
||||
$code .= sprintf(" %s: %s\n", $key, $this->dumper->dump($value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->isAutowired()) {
|
||||
$code .= " autowire: true\n";
|
||||
}
|
||||
|
||||
if ($definition->isAutoconfigured()) {
|
||||
$code .= " autoconfigure: true\n";
|
||||
}
|
||||
|
||||
if ($definition->isAbstract()) {
|
||||
$code .= " abstract: true\n";
|
||||
}
|
||||
|
||||
if ($definition->isLazy()) {
|
||||
$code .= " lazy: true\n";
|
||||
}
|
||||
|
||||
if ($definition->getArguments()) {
|
||||
$code .= sprintf(" arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
|
||||
}
|
||||
|
||||
if ($definition->getProperties()) {
|
||||
$code .= sprintf(" properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
|
||||
}
|
||||
|
||||
if ($definition->getMethodCalls()) {
|
||||
$code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
|
||||
}
|
||||
|
||||
if (!$definition->isShared()) {
|
||||
$code .= " shared: false\n";
|
||||
}
|
||||
|
||||
if (null !== $decoratedService = $definition->getDecoratedService()) {
|
||||
[$decorated, $renamedId, $priority] = $decoratedService;
|
||||
$code .= sprintf(" decorates: %s\n", $decorated);
|
||||
if (null !== $renamedId) {
|
||||
$code .= sprintf(" decoration_inner_name: %s\n", $renamedId);
|
||||
}
|
||||
if (0 !== $priority) {
|
||||
$code .= sprintf(" decoration_priority: %s\n", $priority);
|
||||
}
|
||||
|
||||
$decorationOnInvalid = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
if (\in_array($decorationOnInvalid, [ContainerInterface::IGNORE_ON_INVALID_REFERENCE, ContainerInterface::NULL_ON_INVALID_REFERENCE])) {
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE === $decorationOnInvalid ? 'null' : 'ignore';
|
||||
$code .= sprintf(" decoration_on_invalid: %s\n", $invalidBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
if ($callable = $definition->getFactory()) {
|
||||
if (\is_array($callable) && ['Closure', 'fromCallable'] !== $callable && $definition->getClass() === $callable[0]) {
|
||||
$code .= sprintf(" constructor: %s\n", $callable[1]);
|
||||
} else {
|
||||
$code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
$code .= sprintf(" configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private function addServiceAlias(string $alias, Alias $id): string
|
||||
{
|
||||
$deprecated = '';
|
||||
|
||||
if ($id->isDeprecated()) {
|
||||
$deprecated = " deprecated:\n";
|
||||
|
||||
foreach ($id->getDeprecation('%alias_id%') as $key => $value) {
|
||||
if ('' !== $value) {
|
||||
$deprecated .= sprintf(" %s: %s\n", $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$id->isDeprecated() && $id->isPrivate()) {
|
||||
return sprintf(" %s: '@%s'\n", $alias, $id);
|
||||
}
|
||||
|
||||
if ($id->isPublic()) {
|
||||
$deprecated = " public: true\n".$deprecated;
|
||||
}
|
||||
|
||||
return sprintf(" %s:\n alias: %s\n%s", $alias, $id, $deprecated);
|
||||
}
|
||||
|
||||
private function addServices(): string
|
||||
{
|
||||
if (!$this->container->getDefinitions()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$code = "services:\n";
|
||||
foreach ($this->container->getDefinitions() as $id => $definition) {
|
||||
$code .= $this->addService($id, $definition);
|
||||
}
|
||||
|
||||
$aliases = $this->container->getAliases();
|
||||
foreach ($aliases as $alias => $id) {
|
||||
while (isset($aliases[(string) $id])) {
|
||||
$id = $aliases[(string) $id];
|
||||
}
|
||||
$code .= $this->addServiceAlias($alias, $id);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private function addParameters(): string
|
||||
{
|
||||
if (!$this->container->getParameterBag()->all()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isCompiled());
|
||||
|
||||
return $this->dumper->dump(['parameters' => $parameters], 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps callable to YAML format.
|
||||
*/
|
||||
private function dumpCallable(mixed $callable): mixed
|
||||
{
|
||||
if (\is_array($callable)) {
|
||||
if ($callable[0] instanceof Reference) {
|
||||
$callable = [$this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]];
|
||||
} else {
|
||||
$callable = [$callable[0], $callable[1]];
|
||||
}
|
||||
}
|
||||
|
||||
return $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the value to YAML format.
|
||||
*
|
||||
* @throws RuntimeException When trying to dump object or resource
|
||||
*/
|
||||
private function dumpValue(mixed $value): mixed
|
||||
{
|
||||
if ($value instanceof ServiceClosureArgument) {
|
||||
$value = $value->getValues()[0];
|
||||
|
||||
return new TaggedValue('service_closure', $this->dumpValue($value));
|
||||
}
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
$tag = $value;
|
||||
|
||||
if ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) {
|
||||
if (null === $tag->getIndexAttribute()) {
|
||||
$content = $tag->getTag();
|
||||
} else {
|
||||
$content = [
|
||||
'tag' => $tag->getTag(),
|
||||
'index_by' => $tag->getIndexAttribute(),
|
||||
];
|
||||
|
||||
if (null !== $tag->getDefaultIndexMethod()) {
|
||||
$content['default_index_method'] = $tag->getDefaultIndexMethod();
|
||||
}
|
||||
if (null !== $tag->getDefaultPriorityMethod()) {
|
||||
$content['default_priority_method'] = $tag->getDefaultPriorityMethod();
|
||||
}
|
||||
}
|
||||
if ($excludes = $tag->getExclude()) {
|
||||
if (!\is_array($content)) {
|
||||
$content = ['tag' => $content];
|
||||
}
|
||||
$content['exclude'] = 1 === \count($excludes) ? $excludes[0] : $excludes;
|
||||
}
|
||||
if (!$tag->excludeSelf()) {
|
||||
$content['exclude_self'] = false;
|
||||
}
|
||||
|
||||
return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator', $content);
|
||||
}
|
||||
|
||||
if ($value instanceof IteratorArgument) {
|
||||
$tag = 'iterator';
|
||||
} elseif ($value instanceof ServiceLocatorArgument) {
|
||||
$tag = 'service_locator';
|
||||
} else {
|
||||
throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', get_debug_type($value)));
|
||||
}
|
||||
|
||||
return new TaggedValue($tag, $this->dumpValue($value->getValues()));
|
||||
}
|
||||
|
||||
if (\is_array($value)) {
|
||||
$code = [];
|
||||
foreach ($value as $k => $v) {
|
||||
$code[$k] = $this->dumpValue($v);
|
||||
}
|
||||
|
||||
return $code;
|
||||
} elseif ($value instanceof Reference) {
|
||||
return $this->getServiceCall((string) $value, $value);
|
||||
} elseif ($value instanceof Parameter) {
|
||||
return $this->getParameterCall((string) $value);
|
||||
} elseif ($value instanceof Expression) {
|
||||
return $this->getExpressionCall((string) $value);
|
||||
} elseif ($value instanceof Definition) {
|
||||
return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
|
||||
} elseif ($value instanceof \UnitEnum) {
|
||||
return new TaggedValue('php/const', sprintf('%s::%s', $value::class, $value->name));
|
||||
} elseif ($value instanceof AbstractArgument) {
|
||||
return new TaggedValue('abstract', $value->getText());
|
||||
} elseif (\is_object($value) || \is_resource($value)) {
|
||||
throw new RuntimeException(sprintf('Unable to dump a service container if a parameter is an object or a resource, got "%s".', get_debug_type($value)));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function getServiceCall(string $id, ?Reference $reference = null): string
|
||||
{
|
||||
if (null !== $reference) {
|
||||
switch ($reference->getInvalidBehavior()) {
|
||||
case ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE: break;
|
||||
case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break;
|
||||
case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id);
|
||||
default: return sprintf('@?%s', $id);
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf('@%s', $id);
|
||||
}
|
||||
|
||||
private function getParameterCall(string $id): string
|
||||
{
|
||||
return sprintf('%%%s%%', $id);
|
||||
}
|
||||
|
||||
private function getExpressionCall(string $expression): string
|
||||
{
|
||||
return sprintf('@=%s', $expression);
|
||||
}
|
||||
|
||||
private function prepareParameters(array $parameters, bool $escape = true): array
|
||||
{
|
||||
$filtered = [];
|
||||
foreach ($parameters as $key => $value) {
|
||||
if (\is_array($value)) {
|
||||
$value = $this->prepareParameters($value, $escape);
|
||||
} elseif ($value instanceof Reference || \is_string($value) && str_starts_with($value, '@')) {
|
||||
$value = '@'.$value;
|
||||
}
|
||||
|
||||
$filtered[$key] = $value;
|
||||
}
|
||||
|
||||
return $escape ? $this->escape($filtered) : $filtered;
|
||||
}
|
||||
|
||||
private function escape(array $arguments): array
|
||||
{
|
||||
$args = [];
|
||||
foreach ($arguments as $k => $v) {
|
||||
if (\is_array($v)) {
|
||||
$args[$k] = $this->escape($v);
|
||||
} elseif (\is_string($v)) {
|
||||
$args[$k] = str_replace('%', '%%', $v);
|
||||
} else {
|
||||
$args[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
}
|
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/EnvVarLoaderInterface.php
vendored
Normal file
25
plugins/simplesaml/lib/vendor/symfony/dependency-injection/EnvVarLoaderInterface.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* EnvVarLoaderInterface objects return key/value pairs that are added to the list of available env vars.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface EnvVarLoaderInterface
|
||||
{
|
||||
/**
|
||||
* @return array<string|\Stringable> Key/value pairs that can be accessed using the regular "%env()%" syntax
|
||||
*/
|
||||
public function loadEnvVars(): array;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user