├── Alias.php ├── Argument ├── AbstractArgument.php ├── ArgumentInterface.php ├── BoundArgument.php ├── IteratorArgument.php ├── LazyClosure.php ├── RewindableGenerator.php ├── ServiceClosureArgument.php ├── ServiceLocator.php ├── ServiceLocatorArgument.php └── TaggedIteratorArgument.php ├── Attribute ├── AsAlias.php ├── AsDecorator.php ├── AsTaggedItem.php ├── Autoconfigure.php ├── AutoconfigureTag.php ├── Autowire.php ├── AutowireCallable.php ├── AutowireDecorated.php ├── AutowireInline.php ├── AutowireIterator.php ├── AutowireLocator.php ├── AutowireMethodOf.php ├── AutowireServiceClosure.php ├── Exclude.php ├── Lazy.php ├── TaggedIterator.php ├── TaggedLocator.php ├── Target.php ├── When.php └── WhenNot.php ├── CHANGELOG.md ├── ChildDefinition.php ├── Compiler ├── AbstractRecursivePass.php ├── AliasDeprecatedPublicServicesPass.php ├── AnalyzeServiceReferencesPass.php ├── AttributeAutoconfigurationPass.php ├── AutoAliasServicePass.php ├── AutowireAsDecoratorPass.php ├── AutowirePass.php ├── AutowireRequiredMethodsPass.php ├── AutowireRequiredPropertiesPass.php ├── CheckAliasValidityPass.php ├── CheckArgumentsValidityPass.php ├── CheckCircularReferencesPass.php ├── CheckDefinitionValidityPass.php ├── CheckExceptionOnInvalidReferenceBehaviorPass.php ├── CheckReferenceValidityPass.php ├── CheckTypeDeclarationsPass.php ├── Compiler.php ├── CompilerPassInterface.php ├── DecoratorServicePass.php ├── DefinitionErrorExceptionPass.php ├── ExtensionCompilerPass.php ├── InlineServiceDefinitionsPass.php ├── MergeExtensionConfigurationPass.php ├── PassConfig.php ├── PriorityTaggedServiceTrait.php ├── RegisterAutoconfigureAttributesPass.php ├── RegisterEnvVarProcessorsPass.php ├── RegisterReverseContainerPass.php ├── RegisterServiceSubscribersPass.php ├── RemoveAbstractDefinitionsPass.php ├── RemoveBuildParametersPass.php ├── RemovePrivateAliasesPass.php ├── RemoveUnusedDefinitionsPass.php ├── ReplaceAliasByActualDefinitionPass.php ├── ResolveAutowireInlineAttributesPass.php ├── ResolveBindingsPass.php ├── ResolveChildDefinitionsPass.php ├── ResolveClassPass.php ├── ResolveDecoratorStackPass.php ├── ResolveEnvPlaceholdersPass.php ├── ResolveFactoryClassPass.php ├── ResolveHotPathPass.php ├── ResolveInstanceofConditionalsPass.php ├── ResolveInvalidReferencesPass.php ├── ResolveNamedArgumentsPass.php ├── ResolveNoPreloadPass.php ├── ResolveParameterPlaceHoldersPass.php ├── ResolveReferencesToAliasesPass.php ├── ResolveServiceSubscribersPass.php ├── ResolveTaggedIteratorArgumentPass.php ├── ServiceLocatorTagPass.php ├── ServiceReferenceGraph.php ├── ServiceReferenceGraphEdge.php ├── ServiceReferenceGraphNode.php └── ValidateEnvPlaceholdersPass.php ├── Config ├── ContainerParametersResource.php └── ContainerParametersResourceChecker.php ├── Container.php ├── ContainerBuilder.php ├── ContainerInterface.php ├── Definition.php ├── Dumper ├── Dumper.php ├── DumperInterface.php ├── GraphvizDumper.php ├── PhpDumper.php ├── Preloader.php ├── XmlDumper.php └── YamlDumper.php ├── EnvVarLoaderInterface.php ├── EnvVarProcessor.php ├── EnvVarProcessorInterface.php ├── Exception ├── AutoconfigureFailedException.php ├── AutowiringFailedException.php ├── BadMethodCallException.php ├── EmptyParameterValueException.php ├── EnvNotFoundException.php ├── EnvParameterException.php ├── ExceptionInterface.php ├── InvalidArgumentException.php ├── InvalidParameterTypeException.php ├── LogicException.php ├── OutOfBoundsException.php ├── ParameterCircularReferenceException.php ├── ParameterNotFoundException.php ├── RuntimeException.php ├── ServiceCircularReferenceException.php └── ServiceNotFoundException.php ├── ExpressionLanguage.php ├── ExpressionLanguageProvider.php ├── Extension ├── AbstractExtension.php ├── ConfigurableExtensionInterface.php ├── ConfigurationExtensionInterface.php ├── Extension.php ├── ExtensionInterface.php ├── ExtensionTrait.php └── PrependExtensionInterface.php ├── LICENSE ├── LazyProxy ├── Instantiator │ ├── InstantiatorInterface.php │ ├── LazyServiceInstantiator.php │ └── RealServiceInstantiator.php └── PhpDumper │ ├── DumperInterface.php │ ├── LazyServiceDumper.php │ └── NullDumper.php ├── Loader ├── ClosureLoader.php ├── Configurator │ ├── AbstractConfigurator.php │ ├── AbstractServiceConfigurator.php │ ├── AliasConfigurator.php │ ├── ClosureReferenceConfigurator.php │ ├── ContainerConfigurator.php │ ├── DefaultsConfigurator.php │ ├── EnvConfigurator.php │ ├── FromCallableConfigurator.php │ ├── InlineServiceConfigurator.php │ ├── InstanceofConfigurator.php │ ├── ParametersConfigurator.php │ ├── PrototypeConfigurator.php │ ├── ReferenceConfigurator.php │ ├── ServiceConfigurator.php │ ├── ServicesConfigurator.php │ └── Traits │ │ ├── AbstractTrait.php │ │ ├── ArgumentTrait.php │ │ ├── AutoconfigureTrait.php │ │ ├── AutowireTrait.php │ │ ├── BindTrait.php │ │ ├── CallTrait.php │ │ ├── ClassTrait.php │ │ ├── ConfiguratorTrait.php │ │ ├── ConstructorTrait.php │ │ ├── DecorateTrait.php │ │ ├── DeprecateTrait.php │ │ ├── FactoryTrait.php │ │ ├── FileTrait.php │ │ ├── FromCallableTrait.php │ │ ├── LazyTrait.php │ │ ├── ParentTrait.php │ │ ├── PropertyTrait.php │ │ ├── PublicTrait.php │ │ ├── ShareTrait.php │ │ ├── SyntheticTrait.php │ │ └── TagTrait.php ├── DirectoryLoader.php ├── FileLoader.php ├── GlobFileLoader.php ├── IniFileLoader.php ├── PhpFileLoader.php ├── UndefinedExtensionHandler.php ├── XmlFileLoader.php ├── YamlFileLoader.php └── schema │ └── dic │ └── services │ └── services-1.0.xsd ├── Parameter.php ├── ParameterBag ├── ContainerBag.php ├── ContainerBagInterface.php ├── EnvPlaceholderParameterBag.php ├── FrozenParameterBag.php ├── ParameterBag.php └── ParameterBagInterface.php ├── README.md ├── Reference.php ├── ReverseContainer.php ├── ServiceLocator.php ├── StaticEnvVarLoader.php ├── TaggedContainerInterface.php ├── TypedReference.php ├── Variable.php └── composer.json /Alias.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | class Alias 17 | { 18 | 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.'; 19 | 20 | private array $deprecation = []; 21 | 22 | public function __construct( 23 | private string $id, 24 | private bool $public = false, 25 | ) { 26 | } 27 | 28 | /** 29 | * Checks if this DI Alias should be public or not. 30 | */ 31 | public function isPublic(): bool 32 | { 33 | return $this->public; 34 | } 35 | 36 | /** 37 | * Sets if this Alias is public. 38 | * 39 | * @return $this 40 | */ 41 | public function setPublic(bool $boolean): static 42 | { 43 | $this->public = $boolean; 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * Whether this alias is private. 50 | */ 51 | public function isPrivate(): bool 52 | { 53 | return !$this->public; 54 | } 55 | 56 | /** 57 | * Whether this alias is deprecated, that means it should not be referenced 58 | * anymore. 59 | * 60 | * @param string $package The name of the composer package that is triggering the deprecation 61 | * @param string $version The version of the package that introduced the deprecation 62 | * @param string $message The deprecation message to use 63 | * 64 | * @return $this 65 | * 66 | * @throws InvalidArgumentException when the message template is invalid 67 | */ 68 | public function setDeprecated(string $package, string $version, string $message): static 69 | { 70 | if ('' !== $message) { 71 | if (preg_match('#[\r\n]|\*/#', $message)) { 72 | throw new InvalidArgumentException('Invalid characters found in deprecation template.'); 73 | } 74 | 75 | if (!str_contains($message, '%alias_id%')) { 76 | throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.'); 77 | } 78 | } 79 | 80 | $this->deprecation = ['package' => $package, 'version' => $version, 'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE]; 81 | 82 | return $this; 83 | } 84 | 85 | public function isDeprecated(): bool 86 | { 87 | return (bool) $this->deprecation; 88 | } 89 | 90 | /** 91 | * @param string $id Service id relying on this definition 92 | */ 93 | public function getDeprecation(string $id): array 94 | { 95 | return [ 96 | 'package' => $this->deprecation['package'], 97 | 'version' => $this->deprecation['version'], 98 | 'message' => str_replace('%alias_id%', $id, $this->deprecation['message']), 99 | ]; 100 | } 101 | 102 | public function __toString(): string 103 | { 104 | return $this->id; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Argument/AbstractArgument.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * Represents an abstract service argument, which have to be set by a compiler pass or a DI extension. 16 | */ 17 | final class AbstractArgument 18 | { 19 | private string $text; 20 | private string $context = ''; 21 | 22 | public function __construct(string $text = '') 23 | { 24 | $this->text = trim($text, '. '); 25 | } 26 | 27 | public function setContext(string $context): void 28 | { 29 | $this->context = $context.' is abstract'.('' === $this->text ? '' : ': '); 30 | } 31 | 32 | public function getText(): string 33 | { 34 | return $this->text; 35 | } 36 | 37 | public function getTextWithContext(): string 38 | { 39 | return $this->context.$this->text.'.'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Argument/ArgumentInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * Represents a complex argument containing nested values. 16 | * 17 | * @author Titouan Galopin 18 | */ 19 | interface ArgumentInterface 20 | { 21 | public function getValues(): array; 22 | 23 | public function setValues(array $values): void; 24 | } 25 | -------------------------------------------------------------------------------- /Argument/BoundArgument.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * @author Guilhem Niot 16 | */ 17 | final class BoundArgument implements ArgumentInterface 18 | { 19 | public const SERVICE_BINDING = 0; 20 | public const DEFAULTS_BINDING = 1; 21 | public const INSTANCEOF_BINDING = 2; 22 | 23 | private static int $sequence = 0; 24 | 25 | private ?int $identifier = null; 26 | private ?bool $used = null; 27 | 28 | public function __construct( 29 | private mixed $value, 30 | bool $trackUsage = true, 31 | private int $type = 0, 32 | private ?string $file = null, 33 | ) { 34 | if ($trackUsage) { 35 | $this->identifier = ++self::$sequence; 36 | } else { 37 | $this->used = true; 38 | } 39 | } 40 | 41 | public function getValues(): array 42 | { 43 | return [$this->value, $this->identifier, $this->used, $this->type, $this->file]; 44 | } 45 | 46 | public function setValues(array $values): void 47 | { 48 | if (5 === \count($values)) { 49 | [$this->value, $this->identifier, $this->used, $this->type, $this->file] = $values; 50 | } else { 51 | [$this->value, $this->identifier, $this->used] = $values; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Argument/IteratorArgument.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * Represents a collection of values to lazily iterate over. 16 | * 17 | * @author Titouan Galopin 18 | */ 19 | class IteratorArgument implements ArgumentInterface 20 | { 21 | private array $values; 22 | 23 | public function __construct(array $values) 24 | { 25 | $this->setValues($values); 26 | } 27 | 28 | public function getValues(): array 29 | { 30 | return $this->values; 31 | } 32 | 33 | public function setValues(array $values): void 34 | { 35 | $this->values = $values; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Argument/RewindableGenerator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * @internal 16 | */ 17 | class RewindableGenerator implements \IteratorAggregate, \Countable 18 | { 19 | private \Closure $generator; 20 | private \Closure|int $count; 21 | 22 | public function __construct(callable $generator, int|callable $count) 23 | { 24 | $this->generator = $generator(...); 25 | $this->count = \is_int($count) ? $count : $count(...); 26 | } 27 | 28 | public function getIterator(): \Traversable 29 | { 30 | $g = $this->generator; 31 | 32 | return $g(); 33 | } 34 | 35 | public function count(): int 36 | { 37 | if (!\is_int($count = $this->count)) { 38 | $this->count = $count(); 39 | } 40 | 41 | return $this->count; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Argument/ServiceClosureArgument.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | /** 17 | * Represents a service wrapped in a memoizing closure. 18 | * 19 | * @author Nicolas Grekas 20 | */ 21 | class ServiceClosureArgument implements ArgumentInterface 22 | { 23 | private array $values; 24 | 25 | public function __construct(mixed $value) 26 | { 27 | $this->values = [$value]; 28 | } 29 | 30 | public function getValues(): array 31 | { 32 | return $this->values; 33 | } 34 | 35 | public function setValues(array $values): void 36 | { 37 | if ([0] !== array_keys($values)) { 38 | throw new InvalidArgumentException('A ServiceClosureArgument must hold one and only one value.'); 39 | } 40 | 41 | $this->values = $values; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Argument/ServiceLocator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | * 19 | * @internal 20 | */ 21 | class ServiceLocator extends BaseServiceLocator 22 | { 23 | public function __construct( 24 | private \Closure $factory, 25 | private array $serviceMap, 26 | private ?array $serviceTypes = null, 27 | ) { 28 | parent::__construct($serviceMap); 29 | } 30 | 31 | public function get(string $id): mixed 32 | { 33 | return match (\count($this->serviceMap[$id] ?? [])) { 34 | 0 => parent::get($id), 35 | 1 => $this->serviceMap[$id][0], 36 | default => ($this->factory)(...$this->serviceMap[$id]), 37 | }; 38 | } 39 | 40 | public function getProvidedServices(): array 41 | { 42 | return $this->serviceTypes ??= array_map(fn () => '?', $this->serviceMap); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Argument/ServiceLocatorArgument.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Argument; 13 | 14 | /** 15 | * Represents a closure acting as a service locator. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | class ServiceLocatorArgument implements ArgumentInterface 20 | { 21 | private array $values; 22 | private ?TaggedIteratorArgument $taggedIteratorArgument = null; 23 | 24 | public function __construct(array|TaggedIteratorArgument $values = []) 25 | { 26 | if ($values instanceof TaggedIteratorArgument) { 27 | $this->taggedIteratorArgument = $values; 28 | $values = []; 29 | } 30 | 31 | $this->setValues($values); 32 | } 33 | 34 | public function getTaggedIteratorArgument(): ?TaggedIteratorArgument 35 | { 36 | return $this->taggedIteratorArgument; 37 | } 38 | 39 | public function getValues(): array 40 | { 41 | return $this->values; 42 | } 43 | 44 | public function setValues(array $values): void 45 | { 46 | $this->values = $values; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Attribute/AsAlias.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell under which alias a service should be registered or to use the implemented interface if no parameter is given. 16 | * 17 | * @author Alan Poulain 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] 20 | final class AsAlias 21 | { 22 | /** 23 | * @var list 24 | */ 25 | public array $when = []; 26 | 27 | /** 28 | * @param string|null $id The id of the alias 29 | * @param bool $public Whether to declare the alias public 30 | * @param string|list $when The environments under which the class will be registered as a service (i.e. "dev", "test", "prod") 31 | */ 32 | public function __construct( 33 | public ?string $id = null, 34 | public bool $public = false, 35 | string|array $when = [], 36 | ) { 37 | $this->when = (array) $when; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Attribute/AsDecorator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | 16 | /** 17 | * Declares a decorating service. 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS)] 20 | class AsDecorator 21 | { 22 | /** 23 | * @param string $decorates The service id to decorate 24 | * @param int $priority The priority of this decoration when multiple decorators are declared for the same service 25 | * @param int $onInvalid The behavior to adopt when the decoration is invalid; must be one of the {@see ContainerInterface} constants 26 | */ 27 | public function __construct( 28 | public string $decorates, 29 | public int $priority = 0, 30 | public int $onInvalid = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 31 | ) { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Attribute/AsTaggedItem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell under which index and priority a service class should be found in tagged iterators/locators. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] 20 | class AsTaggedItem 21 | { 22 | /** 23 | * @param string|null $index The property or method to use to index the item in the locator 24 | * @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the locator 25 | */ 26 | public function __construct( 27 | public ?string $index = null, 28 | public ?int $priority = null, 29 | ) { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Attribute/Autoconfigure.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell how a base type should be autoconfigured. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] 20 | class Autoconfigure 21 | { 22 | /** 23 | * @param array>|string[]|null $tags The tags to add to the service 24 | * @param array>|null $calls The calls to be made when instantiating the service 25 | * @param array|null $bind The bindings to declare for the service 26 | * @param bool|string|null $lazy Whether the service is lazy-loaded 27 | * @param bool|null $public Whether to declare the service as public 28 | * @param bool|null $shared Whether to declare the service as shared 29 | * @param bool|null $autowire Whether to declare the service as autowired 30 | * @param array|null $properties The properties to define when creating the service 31 | * @param array{string, string}|string|null $configurator A PHP function, reference or an array containing a class/reference and a method to call after the service is fully initialized 32 | * @param string|null $constructor The public static method to use to instantiate the service 33 | */ 34 | public function __construct( 35 | public ?array $tags = null, 36 | public ?array $calls = null, 37 | public ?array $bind = null, 38 | public bool|string|null $lazy = null, 39 | public ?bool $public = null, 40 | public ?bool $shared = null, 41 | public ?bool $autowire = null, 42 | public ?array $properties = null, 43 | public array|string|null $configurator = null, 44 | public ?string $constructor = null, 45 | ) { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Attribute/AutoconfigureTag.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell how a base type should be tagged. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] 20 | class AutoconfigureTag extends Autoconfigure 21 | { 22 | /** 23 | * @param string|null $name The tag name to add 24 | * @param array $attributes The tag attributes to attach to the tag 25 | */ 26 | public function __construct(?string $name = null, array $attributes = []) 27 | { 28 | parent::__construct( 29 | tags: [ 30 | [$name ?? 0 => $attributes], 31 | ] 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Attribute/AutowireCallable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Exception\LogicException; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | 18 | /** 19 | * Attribute to tell which callable to give to an argument of type Closure. 20 | */ 21 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 22 | class AutowireCallable extends AutowireInline 23 | { 24 | /** 25 | * @param string|array|null $callable The callable to autowire 26 | * @param string|null $service The service containing the callable to autowire 27 | * @param string|null $method The method name that will be autowired 28 | * @param bool|class-string $lazy Whether to use lazy-loading for this argument 29 | */ 30 | public function __construct( 31 | string|array|null $callable = null, 32 | ?string $service = null, 33 | ?string $method = null, 34 | bool|string $lazy = false, 35 | ) { 36 | if (!(null !== $callable xor null !== $service)) { 37 | throw new LogicException('#[AutowireCallable] attribute must declare exactly one of $callable or $service.'); 38 | } 39 | if (null === $service && null !== $method) { 40 | throw new LogicException('#[AutowireCallable] attribute cannot have a $method without a $service.'); 41 | } 42 | 43 | Autowire::__construct($callable ?? [new Reference($service), $method ?? '__invoke'], lazy: $lazy); 44 | } 45 | 46 | public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition 47 | { 48 | return (new Definition($type = \is_array($this->lazy) ? current($this->lazy) : ($type ?: 'Closure'))) 49 | ->setFactory(['Closure', 'fromCallable']) 50 | ->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value]) 51 | ->setLazy($this->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Attribute/AutowireDecorated.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * Autowires the inner object of decorating services. 16 | */ 17 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 18 | class AutowireDecorated 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /Attribute/AutowireInline.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Exception\LogicException; 16 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 17 | 18 | /** 19 | * Allows inline service definition for an argument. 20 | * 21 | * Using this attribute on a class autowires a new instance 22 | * which is not shared between different services. 23 | * 24 | * $class a FQCN, or an array to define a factory. 25 | * Use the "@" prefix to reference a service. 26 | * 27 | * @author Ismail Özgün Turan 28 | */ 29 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 30 | class AutowireInline extends Autowire 31 | { 32 | public function __construct(string|array|null $class = null, array $arguments = [], array $calls = [], array $properties = [], ?string $parent = null, bool|string $lazy = false) 33 | { 34 | if (null === $class && null === $parent) { 35 | throw new LogicException('#[AutowireInline] attribute should declare either $class or $parent.'); 36 | } 37 | 38 | parent::__construct([ 39 | \is_array($class) ? 'factory' : 'class' => $class, 40 | 'arguments' => $arguments, 41 | 'calls' => $calls, 42 | 'properties' => $properties, 43 | 'parent' => $parent, 44 | ], lazy: $lazy); 45 | } 46 | 47 | public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition 48 | { 49 | static $parseDefinition; 50 | static $yamlLoader; 51 | 52 | $parseDefinition ??= new \ReflectionMethod(YamlFileLoader::class, 'parseDefinition'); 53 | $yamlLoader ??= $parseDefinition->getDeclaringClass()->newInstanceWithoutConstructor(); 54 | 55 | if (isset($value['factory'])) { 56 | $value['class'] = $type; 57 | $value['factory'][0] ??= $type; 58 | $value['factory'][1] ??= '__invoke'; 59 | } 60 | $class = $parameter->getDeclaringClass(); 61 | 62 | return $parseDefinition->invoke($yamlLoader, $class->name, $value, $class->getFileName(), ['autowire' => true], true); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Attribute/AutowireIterator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; 15 | 16 | /** 17 | * Autowires an iterator of services based on a tag name. 18 | */ 19 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 20 | class AutowireIterator extends Autowire 21 | { 22 | /** 23 | * @see ServiceSubscriberInterface::getSubscribedServices() 24 | * 25 | * @param string $tag A tag name to search for to populate the iterator 26 | * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection 27 | * @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 28 | * @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 29 | * @param string|array $exclude A service id or a list of service ids to exclude 30 | * @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator 31 | */ 32 | public function __construct( 33 | string $tag, 34 | ?string $indexAttribute = null, 35 | ?string $defaultIndexMethod = null, 36 | ?string $defaultPriorityMethod = null, 37 | string|array $exclude = [], 38 | bool $excludeSelf = true, 39 | ) { 40 | parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Attribute/AutowireMethodOf.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Reference; 16 | 17 | /** 18 | * Tells which method should be turned into a Closure based on the name of the parameter it's attached to. 19 | */ 20 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 21 | class AutowireMethodOf extends AutowireCallable 22 | { 23 | /** 24 | * @param string $service The service containing the method to autowire 25 | * @param bool|class-string $lazy Whether to use lazy-loading for this argument 26 | */ 27 | public function __construct(string $service, bool|string $lazy = false) 28 | { 29 | parent::__construct([new Reference($service)], lazy: $lazy); 30 | } 31 | 32 | public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition 33 | { 34 | $value[1] = $parameter->name; 35 | 36 | return parent::buildDefinition($value, $type, $parameter); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Attribute/AutowireServiceClosure.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; 15 | use Symfony\Component\DependencyInjection\Reference; 16 | 17 | /** 18 | * Attribute to wrap a service in a closure that returns it. 19 | */ 20 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 21 | class AutowireServiceClosure extends Autowire 22 | { 23 | /** 24 | * @param string $service The service id to wrap in the closure 25 | */ 26 | public function __construct(string $service) 27 | { 28 | parent::__construct(new ServiceClosureArgument(new Reference($service))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Attribute/Exclude.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell the class should not be registered as service. 16 | * 17 | * @author Grégoire Pineau 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS)] 20 | class Exclude 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /Attribute/Lazy.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PARAMETER)] 15 | class Lazy 16 | { 17 | public function __construct( 18 | public bool|string|null $lazy = true, 19 | ) { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Attribute/TaggedIterator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * Autowires an iterator of services based on a tag name. 16 | * 17 | * @deprecated since Symfony 7.1, use {@see AutowireIterator} instead. 18 | */ 19 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 20 | class TaggedIterator extends AutowireIterator 21 | { 22 | /** 23 | * @param string $tag The tag to look for to populate the iterator 24 | * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection 25 | * @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 26 | * @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 27 | * @param string|string[] $exclude A service id or a list of service ids to exclude 28 | * @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator 29 | */ 30 | public function __construct( 31 | public string $tag, 32 | public ?string $indexAttribute = null, 33 | public ?string $defaultIndexMethod = null, 34 | public ?string $defaultPriorityMethod = null, 35 | public string|array $exclude = [], 36 | public bool $excludeSelf = true, 37 | ) { 38 | trigger_deprecation('symfony/dependency-injection', '7.1', 'The "%s" attribute is deprecated, use "%s" instead.', self::class, AutowireIterator::class); 39 | 40 | parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Attribute/TaggedLocator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * Autowires a locator of services based on a tag name. 16 | * 17 | * @deprecated since Symfony 7.1, use {@see AutowireLocator} instead. 18 | */ 19 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 20 | class TaggedLocator extends AutowireLocator 21 | { 22 | /** 23 | * @param string $tag The tag to look for to populate the locator 24 | * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection 25 | * @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 26 | * @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 27 | * @param string|string[] $exclude A service id or a list of service ids to exclude 28 | * @param bool $excludeSelf Whether to automatically exclude the referencing service from the locator 29 | */ 30 | public function __construct( 31 | public string $tag, 32 | public ?string $indexAttribute = null, 33 | public ?string $defaultIndexMethod = null, 34 | public ?string $defaultPriorityMethod = null, 35 | public string|array $exclude = [], 36 | public bool $excludeSelf = true, 37 | ) { 38 | trigger_deprecation('symfony/dependency-injection', '7.1', 'The "%s" attribute is deprecated, use "%s" instead.', self::class, AutowireLocator::class); 39 | 40 | parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Attribute/Target.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | use Symfony\Component\DependencyInjection\Exception\LogicException; 16 | 17 | /** 18 | * An attribute to tell how a dependency is used and hint named autowiring aliases. 19 | * 20 | * @author Nicolas Grekas 21 | */ 22 | #[\Attribute(\Attribute::TARGET_PARAMETER)] 23 | final class Target 24 | { 25 | /** 26 | * @param string|null $name The name of the target autowiring alias 27 | */ 28 | public function __construct(public ?string $name = null) 29 | { 30 | } 31 | 32 | public function getParsedName(): string 33 | { 34 | if (null === $this->name) { 35 | 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__)); 36 | } 37 | 38 | return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->name)))); 39 | } 40 | 41 | public static function parseName(\ReflectionParameter $parameter, ?self &$attribute = null, ?string &$parsedName = null): string 42 | { 43 | $attribute = null; 44 | if (!$target = $parameter->getAttributes(self::class)[0] ?? null) { 45 | $parsedName = (new self($parameter->name))->getParsedName(); 46 | 47 | return $parameter->name; 48 | } 49 | 50 | $attribute = $target->newInstance(); 51 | $name = $attribute->name ??= $parameter->name; 52 | $parsedName = $attribute->getParsedName(); 53 | 54 | if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $parsedName)) { 55 | if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) { 56 | $function = $function->class.'::'.$function->name; 57 | } else { 58 | $function = $function->name; 59 | } 60 | 61 | throw new InvalidArgumentException(\sprintf('Invalid #[Target] name "%s" on parameter "$%s" of "%s()": the first character must be a letter.', $name, $parameter->name, $function)); 62 | } 63 | 64 | return preg_match('/^[a-zA-Z0-9_\x7f-\xff]++$/', $name) ? $name : $parsedName; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Attribute/When.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell under which environment this class should be registered as a service. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)] 20 | class When 21 | { 22 | /** 23 | * @param string $env The environment under which the class will be registered as a service (i.e. "dev", "test", "prod") 24 | */ 25 | public function __construct(public string $env) 26 | { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Attribute/WhenNot.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Attribute; 13 | 14 | /** 15 | * An attribute to tell under which environment this class should NOT be registered as a service. 16 | * 17 | * @author Alexandre Daubois 18 | */ 19 | #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)] 20 | class WhenNot 21 | { 22 | public function __construct( 23 | public string $env, 24 | ) { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ChildDefinition.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException; 16 | 17 | /** 18 | * This definition extends another definition. 19 | * 20 | * @author Johannes M. Schmitt 21 | */ 22 | class ChildDefinition extends Definition 23 | { 24 | /** 25 | * @param string $parent The id of Definition instance to decorate 26 | */ 27 | public function __construct( 28 | private string $parent, 29 | ) { 30 | } 31 | 32 | /** 33 | * Returns the Definition to inherit from. 34 | */ 35 | public function getParent(): string 36 | { 37 | return $this->parent; 38 | } 39 | 40 | /** 41 | * Sets the Definition to inherit from. 42 | * 43 | * @return $this 44 | */ 45 | public function setParent(string $parent): static 46 | { 47 | $this->parent = $parent; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * Gets an argument to pass to the service constructor/factory method. 54 | * 55 | * If replaceArgument() has been used to replace an argument, this method 56 | * will return the replacement value. 57 | * 58 | * @throws OutOfBoundsException When the argument does not exist 59 | */ 60 | public function getArgument(int|string $index): mixed 61 | { 62 | if (\array_key_exists('index_'.$index, $this->arguments)) { 63 | return $this->arguments['index_'.$index]; 64 | } 65 | 66 | return parent::getArgument($index); 67 | } 68 | 69 | /** 70 | * You should always use this method when overwriting existing arguments 71 | * of the parent definition. 72 | * 73 | * If you directly call setArguments() keep in mind that you must follow 74 | * certain conventions when you want to overwrite the arguments of the 75 | * parent definition, otherwise your arguments will only be appended. 76 | * 77 | * @return $this 78 | * 79 | * @throws InvalidArgumentException when $index isn't an integer 80 | */ 81 | public function replaceArgument(int|string $index, mixed $value): static 82 | { 83 | if (\is_int($index)) { 84 | $this->arguments['index_'.$index] = $value; 85 | } elseif (str_starts_with($index, '$')) { 86 | $this->arguments[$index] = $value; 87 | } else { 88 | throw new InvalidArgumentException('The argument must be an existing index or the name of a constructor\'s parameter.'); 89 | } 90 | 91 | return $this; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Compiler/AliasDeprecatedPublicServicesPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | 18 | final class AliasDeprecatedPublicServicesPass extends AbstractRecursivePass 19 | { 20 | protected bool $skipScalars = true; 21 | 22 | private array $aliases = []; 23 | 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->findTaggedServiceIds('container.private') as $id => $tags) { 27 | if (null === $package = $tags[0]['package'] ?? null) { 28 | throw new InvalidArgumentException(\sprintf('The "package" attribute is mandatory for the "container.private" tag on the "%s" service.', $id)); 29 | } 30 | 31 | if (null === $version = $tags[0]['version'] ?? null) { 32 | throw new InvalidArgumentException(\sprintf('The "version" attribute is mandatory for the "container.private" tag on the "%s" service.', $id)); 33 | } 34 | 35 | $definition = $container->getDefinition($id); 36 | if (!$definition->isPublic() || $definition->isPrivate()) { 37 | continue; 38 | } 39 | 40 | $container 41 | ->setAlias($id, $aliasId = '.container.private.'.$id) 42 | ->setPublic(true) 43 | ->setDeprecated($package, $version, 'Accessing the "%alias_id%" service directly from the container is deprecated, use dependency injection instead.'); 44 | 45 | $container->setDefinition($aliasId, $definition); 46 | 47 | $this->aliases[$id] = $aliasId; 48 | } 49 | 50 | parent::process($container); 51 | } 52 | 53 | protected function processValue(mixed $value, bool $isRoot = false): mixed 54 | { 55 | if ($value instanceof Reference && isset($this->aliases[$id = (string) $value])) { 56 | return new Reference($this->aliases[$id], $value->getInvalidBehavior()); 57 | } 58 | 59 | return parent::processValue($value, $isRoot); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Compiler/AutoAliasServicePass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Alias; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 17 | 18 | /** 19 | * Sets a service to be an alias of another one, given a format pattern. 20 | */ 21 | class AutoAliasServicePass implements CompilerPassInterface 22 | { 23 | public function process(ContainerBuilder $container): void 24 | { 25 | foreach ($container->findTaggedServiceIds('auto_alias') as $serviceId => $tags) { 26 | foreach ($tags as $tag) { 27 | if (!isset($tag['format'])) { 28 | throw new InvalidArgumentException(\sprintf('Missing tag information "format" on auto_alias service "%s".', $serviceId)); 29 | } 30 | 31 | $aliasId = $container->getParameterBag()->resolveValue($tag['format']); 32 | if ($container->hasDefinition($aliasId) || $container->hasAlias($aliasId)) { 33 | $alias = new Alias($aliasId, $container->getDefinition($serviceId)->isPublic()); 34 | $container->setAlias($serviceId, $alias); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Compiler/AutowireAsDecoratorPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Attribute\AsDecorator; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Definition; 17 | 18 | /** 19 | * Reads #[AsDecorator] attributes on definitions that are autowired 20 | * and don't have the "container.ignore_attributes" tag. 21 | */ 22 | final class AutowireAsDecoratorPass implements CompilerPassInterface 23 | { 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->getDefinitions() as $definition) { 27 | if ($this->accept($definition) && $reflectionClass = $container->getReflectionClass($definition->getClass(), false)) { 28 | $this->processClass($definition, $reflectionClass); 29 | } 30 | } 31 | } 32 | 33 | private function accept(Definition $definition): bool 34 | { 35 | return !$definition->hasTag('container.ignore_attributes') && $definition->isAutowired(); 36 | } 37 | 38 | private function processClass(Definition $definition, \ReflectionClass $reflectionClass): void 39 | { 40 | foreach ($reflectionClass->getAttributes(AsDecorator::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) { 41 | $attribute = $attribute->newInstance(); 42 | 43 | $definition->setDecoratedService($attribute->decorates, null, $attribute->priority, $attribute->onInvalid); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Compiler/AutowireRequiredMethodsPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Contracts\Service\Attribute\Required; 16 | 17 | /** 18 | * Looks for definitions with autowiring enabled and registers their corresponding "#[Required]" methods as setters. 19 | * 20 | * @author Nicolas Grekas 21 | */ 22 | class AutowireRequiredMethodsPass extends AbstractRecursivePass 23 | { 24 | protected bool $skipScalars = true; 25 | 26 | protected function processValue(mixed $value, bool $isRoot = false): mixed 27 | { 28 | $value = parent::processValue($value, $isRoot); 29 | 30 | if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) { 31 | return $value; 32 | } 33 | if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) { 34 | return $value; 35 | } 36 | 37 | $alreadyCalledMethods = []; 38 | $withers = []; 39 | 40 | foreach ($value->getMethodCalls() as [$method]) { 41 | $alreadyCalledMethods[strtolower($method)] = true; 42 | } 43 | 44 | foreach ($reflectionClass->getMethods() as $reflectionMethod) { 45 | $r = $reflectionMethod; 46 | 47 | if ($r->isConstructor() || isset($alreadyCalledMethods[strtolower($r->name)])) { 48 | continue; 49 | } 50 | 51 | while (true) { 52 | if ($r->getAttributes(Required::class)) { 53 | if ($this->isWither($r, $r->getDocComment() ?: '')) { 54 | $withers[] = [$r->name, [], true]; 55 | } else { 56 | $value->addMethodCall($r->name, []); 57 | } 58 | break; 59 | } 60 | try { 61 | $r = $r->getPrototype(); 62 | } catch (\ReflectionException) { 63 | break; // method has no prototype 64 | } 65 | } 66 | } 67 | 68 | if ($withers) { 69 | // Prepend withers to prevent creating circular loops 70 | $setters = $value->getMethodCalls(); 71 | $value->setMethodCalls($withers); 72 | foreach ($setters as $call) { 73 | $value->addMethodCall($call[0], $call[1], $call[2] ?? false); 74 | } 75 | } 76 | 77 | return $value; 78 | } 79 | 80 | private function isWither(\ReflectionMethod $reflectionMethod, string $doc): bool 81 | { 82 | $match = preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++(static|\$this)[\s\*]#i', $doc, $matches); 83 | if ($match && 'static' === $matches[1]) { 84 | return true; 85 | } 86 | 87 | if ($match && '$this' === $matches[1]) { 88 | return false; 89 | } 90 | 91 | $reflectionType = $reflectionMethod->hasReturnType() ? $reflectionMethod->getReturnType() : null; 92 | 93 | return $reflectionType instanceof \ReflectionNamedType && 'static' === $reflectionType->getName(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Compiler/AutowireRequiredPropertiesPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | use Symfony\Component\DependencyInjection\TypedReference; 17 | use Symfony\Contracts\Service\Attribute\Required; 18 | 19 | /** 20 | * Looks for definitions with autowiring enabled and registers their corresponding "#[Required]" properties. 21 | * 22 | * @author Sebastien Morel (Plopix) 23 | * @author Nicolas Grekas 24 | */ 25 | class AutowireRequiredPropertiesPass extends AbstractRecursivePass 26 | { 27 | protected bool $skipScalars = true; 28 | 29 | protected function processValue(mixed $value, bool $isRoot = false): mixed 30 | { 31 | $value = parent::processValue($value, $isRoot); 32 | 33 | if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) { 34 | return $value; 35 | } 36 | if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) { 37 | return $value; 38 | } 39 | 40 | $properties = $value->getProperties(); 41 | foreach ($reflectionClass->getProperties() as $reflectionProperty) { 42 | if (!($type = $reflectionProperty->getType()) instanceof \ReflectionNamedType) { 43 | continue; 44 | } 45 | if (!$reflectionProperty->getAttributes(Required::class)) { 46 | continue; 47 | } 48 | if (\array_key_exists($name = $reflectionProperty->getName(), $properties)) { 49 | continue; 50 | } 51 | 52 | $type = $type->getName(); 53 | $value->setProperty($name, new TypedReference($type, $type, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name)); 54 | } 55 | 56 | return $value; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Compiler/CheckAliasValidityPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\RuntimeException; 16 | 17 | /** 18 | * This pass validates aliases, it provides the following checks: 19 | * 20 | * - An alias which happens to be an interface must resolve to a service implementing this interface. This ensures injecting the aliased interface won't cause a type error at runtime. 21 | */ 22 | class CheckAliasValidityPass implements CompilerPassInterface 23 | { 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->getAliases() as $id => $alias) { 27 | try { 28 | if (!$container->hasDefinition((string) $alias)) { 29 | continue; 30 | } 31 | 32 | $target = $container->getDefinition((string) $alias); 33 | if (null === $target->getClass() || null !== $target->getFactory()) { 34 | continue; 35 | } 36 | 37 | $reflection = $container->getReflectionClass($id); 38 | if (null === $reflection || !$reflection->isInterface()) { 39 | continue; 40 | } 41 | 42 | $targetReflection = $container->getReflectionClass($target->getClass()); 43 | if (null !== $targetReflection && !$targetReflection->implementsInterface($id)) { 44 | throw new RuntimeException(\sprintf('Invalid alias definition: alias "%s" is referencing class "%s" but this class does not implement "%s". Because this alias is an interface, "%s" must implement "%s".', $id, $target->getClass(), $id, $target->getClass(), $id)); 45 | } 46 | } catch (\ReflectionException) { 47 | continue; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Compiler/CheckCircularReferencesPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; 16 | 17 | /** 18 | * Checks your services for circular references. 19 | * 20 | * References from method calls are ignored since we might be able to resolve 21 | * these references depending on the order in which services are called. 22 | * 23 | * Circular reference from method calls will only be detected at run-time. 24 | * 25 | * @author Johannes M. Schmitt 26 | */ 27 | class CheckCircularReferencesPass implements CompilerPassInterface 28 | { 29 | private array $currentPath; 30 | private array $checkedNodes; 31 | private array $checkedLazyNodes; 32 | 33 | /** 34 | * Checks the ContainerBuilder object for circular references. 35 | */ 36 | public function process(ContainerBuilder $container): void 37 | { 38 | $graph = $container->getCompiler()->getServiceReferenceGraph(); 39 | 40 | $this->checkedNodes = []; 41 | foreach ($graph->getNodes() as $id => $node) { 42 | $this->currentPath = [$id]; 43 | 44 | $this->checkOutEdges($node->getOutEdges()); 45 | } 46 | } 47 | 48 | /** 49 | * Checks for circular references. 50 | * 51 | * @param ServiceReferenceGraphEdge[] $edges An array of Edges 52 | * 53 | * @throws ServiceCircularReferenceException when a circular reference is found 54 | */ 55 | private function checkOutEdges(array $edges): void 56 | { 57 | foreach ($edges as $edge) { 58 | $node = $edge->getDestNode(); 59 | $id = $node->getId(); 60 | 61 | if (!empty($this->checkedNodes[$id])) { 62 | continue; 63 | } 64 | 65 | $isLeaf = (bool) $node->getValue(); 66 | $isConcrete = !$edge->isLazy() && !$edge->isWeak(); 67 | 68 | // Skip already checked lazy services if they are still lazy. Will not gain any new information. 69 | if (!empty($this->checkedLazyNodes[$id]) && (!$isLeaf || !$isConcrete)) { 70 | continue; 71 | } 72 | 73 | // Process concrete references, otherwise defer check circular references for lazy edges. 74 | if (!$isLeaf || $isConcrete) { 75 | $searchKey = array_search($id, $this->currentPath); 76 | $this->currentPath[] = $id; 77 | 78 | if (false !== $searchKey) { 79 | throw new ServiceCircularReferenceException($id, \array_slice($this->currentPath, $searchKey)); 80 | } 81 | 82 | $this->checkOutEdges($node->getOutEdges()); 83 | 84 | $this->checkedNodes[$id] = true; 85 | unset($this->checkedLazyNodes[$id]); 86 | } else { 87 | $this->checkedLazyNodes[$id] = true; 88 | } 89 | 90 | array_pop($this->currentPath); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Compiler/CheckReferenceValidityPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Exception\RuntimeException; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | 18 | /** 19 | * Checks the validity of references. 20 | * 21 | * The following checks are performed by this pass: 22 | * - target definitions are not abstract 23 | * 24 | * @author Johannes M. Schmitt 25 | */ 26 | class CheckReferenceValidityPass extends AbstractRecursivePass 27 | { 28 | protected bool $skipScalars = true; 29 | 30 | protected function processValue(mixed $value, bool $isRoot = false): mixed 31 | { 32 | if ($isRoot && $value instanceof Definition && ($value->isSynthetic() || $value->isAbstract())) { 33 | return $value; 34 | } 35 | if ($value instanceof Reference && $this->container->hasDefinition((string) $value)) { 36 | $targetDefinition = $this->container->getDefinition((string) $value); 37 | 38 | if ($targetDefinition->isAbstract()) { 39 | 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)); 40 | } 41 | } 42 | 43 | return parent::processValue($value, $isRoot); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Compiler/Compiler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\EnvParameterException; 16 | 17 | /** 18 | * This class is used to remove circular dependencies between individual passes. 19 | * 20 | * @author Johannes M. Schmitt 21 | */ 22 | class Compiler 23 | { 24 | private PassConfig $passConfig; 25 | private array $log = []; 26 | private ServiceReferenceGraph $serviceReferenceGraph; 27 | 28 | public function __construct() 29 | { 30 | $this->passConfig = new PassConfig(); 31 | $this->serviceReferenceGraph = new ServiceReferenceGraph(); 32 | } 33 | 34 | public function getPassConfig(): PassConfig 35 | { 36 | return $this->passConfig; 37 | } 38 | 39 | public function getServiceReferenceGraph(): ServiceReferenceGraph 40 | { 41 | return $this->serviceReferenceGraph; 42 | } 43 | 44 | public function addPass(CompilerPassInterface $pass, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): void 45 | { 46 | $this->passConfig->addPass($pass, $type, $priority); 47 | } 48 | 49 | /** 50 | * @final 51 | */ 52 | public function log(CompilerPassInterface $pass, string $message): void 53 | { 54 | if (str_contains($message, "\n")) { 55 | $message = str_replace("\n", "\n".$pass::class.': ', trim($message)); 56 | } 57 | 58 | $this->log[] = $pass::class.': '.$message; 59 | } 60 | 61 | public function getLog(): array 62 | { 63 | return $this->log; 64 | } 65 | 66 | /** 67 | * Run the Compiler and process all Passes. 68 | */ 69 | public function compile(ContainerBuilder $container): void 70 | { 71 | try { 72 | foreach ($this->passConfig->getPasses() as $pass) { 73 | $pass->process($container); 74 | } 75 | } catch (\Exception $e) { 76 | $usedEnvs = []; 77 | $prev = $e; 78 | 79 | do { 80 | $msg = $prev->getMessage(); 81 | 82 | if ($msg !== $resolvedMsg = $container->resolveEnvPlaceholders($msg, null, $usedEnvs)) { 83 | $r = new \ReflectionProperty($prev, 'message'); 84 | $r->setValue($prev, $resolvedMsg); 85 | } 86 | } while ($prev = $prev->getPrevious()); 87 | 88 | if ($usedEnvs) { 89 | $e = new EnvParameterException($usedEnvs, $e); 90 | } 91 | 92 | throw $e; 93 | } finally { 94 | $this->getServiceReferenceGraph()->clear(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Compiler/CompilerPassInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * Interface that must be implemented by compilation passes. 18 | * 19 | * @author Johannes M. Schmitt 20 | */ 21 | interface CompilerPassInterface 22 | { 23 | /** 24 | * You can modify the container here before it is dumped to PHP code. 25 | * 26 | * @return void 27 | */ 28 | public function process(ContainerBuilder $container); 29 | } 30 | -------------------------------------------------------------------------------- /Compiler/ExtensionCompilerPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * A pass to automatically process extensions if they implement 18 | * CompilerPassInterface. 19 | * 20 | * @author Wouter J 21 | */ 22 | class ExtensionCompilerPass implements CompilerPassInterface 23 | { 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->getExtensions() as $extension) { 27 | if (!$extension instanceof CompilerPassInterface) { 28 | continue; 29 | } 30 | 31 | $extension->process($container); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Compiler/RegisterEnvVarProcessorsPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\EnvVarProcessor; 16 | use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; 17 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 18 | use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; 19 | use Symfony\Component\DependencyInjection\Reference; 20 | 21 | /** 22 | * Creates the container.env_var_processors_locator service. 23 | * 24 | * @author Nicolas Grekas 25 | */ 26 | class RegisterEnvVarProcessorsPass implements CompilerPassInterface 27 | { 28 | private const ALLOWED_TYPES = ['array', 'bool', 'float', 'int', 'string', \BackedEnum::class]; 29 | 30 | public function process(ContainerBuilder $container): void 31 | { 32 | $bag = $container->getParameterBag(); 33 | $types = []; 34 | $processors = []; 35 | foreach ($container->findTaggedServiceIds('container.env_var_processor') as $id => $tags) { 36 | if (!$r = $container->getReflectionClass($class = $container->getDefinition($id)->getClass())) { 37 | throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); 38 | } elseif (!$r->isSubclassOf(EnvVarProcessorInterface::class)) { 39 | throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class)); 40 | } 41 | foreach ($class::getProvidedTypes() as $prefix => $type) { 42 | $processors[$prefix] = new Reference($id); 43 | $types[$prefix] = self::validateProvidedTypes($type, $class); 44 | } 45 | } 46 | 47 | if ($bag instanceof EnvPlaceholderParameterBag) { 48 | foreach (EnvVarProcessor::getProvidedTypes() as $prefix => $type) { 49 | if (!isset($types[$prefix])) { 50 | $types[$prefix] = self::validateProvidedTypes($type, EnvVarProcessor::class); 51 | } 52 | } 53 | $bag->setProvidedTypes($types); 54 | } 55 | 56 | if ($processors) { 57 | $container->setAlias('container.env_var_processors_locator', (string) ServiceLocatorTagPass::register($container, $processors)) 58 | ->setPublic(true) 59 | ; 60 | } 61 | } 62 | 63 | private static function validateProvidedTypes(string $types, string $class): array 64 | { 65 | $types = explode('|', $types); 66 | 67 | foreach ($types as $type) { 68 | if (!\in_array($type, self::ALLOWED_TYPES, true)) { 69 | throw new InvalidArgumentException(\sprintf('Invalid type "%s" returned by "%s::getProvidedTypes()", expected one of "%s".', $type, $class, implode('", "', self::ALLOWED_TYPES))); 70 | } 71 | } 72 | 73 | return $types; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Compiler/RegisterReverseContainerPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\ContainerInterface; 17 | use Symfony\Component\DependencyInjection\Definition; 18 | use Symfony\Component\DependencyInjection\Reference; 19 | 20 | /** 21 | * @author Nicolas Grekas 22 | */ 23 | class RegisterReverseContainerPass implements CompilerPassInterface 24 | { 25 | public function __construct( 26 | private bool $beforeRemoving, 27 | ) { 28 | } 29 | 30 | public function process(ContainerBuilder $container): void 31 | { 32 | if (!$container->hasDefinition('reverse_container')) { 33 | return; 34 | } 35 | 36 | $refType = $this->beforeRemoving ? ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; 37 | $services = []; 38 | foreach ($container->findTaggedServiceIds('container.reversible') as $id => $tags) { 39 | $services[$id] = new Reference($id, $refType); 40 | } 41 | 42 | if ($this->beforeRemoving) { 43 | // prevent inlining of the reverse container 44 | $services['reverse_container'] = new Reference('reverse_container', $refType); 45 | } 46 | $locator = $container->getDefinition('reverse_container')->getArgument(1); 47 | 48 | if ($locator instanceof Reference) { 49 | $locator = $container->getDefinition((string) $locator); 50 | } 51 | if ($locator instanceof Definition) { 52 | foreach ($services as $id => $ref) { 53 | $services[$id] = new ServiceClosureArgument($ref); 54 | } 55 | $locator->replaceArgument(0, $services); 56 | } else { 57 | $locator->setValues($services); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Compiler/RemoveAbstractDefinitionsPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * Removes abstract Definitions. 18 | */ 19 | class RemoveAbstractDefinitionsPass implements CompilerPassInterface 20 | { 21 | /** 22 | * Removes abstract definitions from the ContainerBuilder. 23 | */ 24 | public function process(ContainerBuilder $container): void 25 | { 26 | foreach ($container->getDefinitions() as $id => $definition) { 27 | if ($definition->isAbstract()) { 28 | $container->removeDefinition($id); 29 | $container->log($this, \sprintf('Removed service "%s"; reason: abstract.', $id)); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Compiler/RemoveBuildParametersPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | class RemoveBuildParametersPass implements CompilerPassInterface 17 | { 18 | /** 19 | * @var array 20 | */ 21 | private array $removedParameters = []; 22 | 23 | public function process(ContainerBuilder $container): void 24 | { 25 | $parameterBag = $container->getParameterBag(); 26 | $this->removedParameters = []; 27 | 28 | foreach ($parameterBag->all() as $name => $value) { 29 | if ('.' === ($name[0] ?? '')) { 30 | $this->removedParameters[$name] = $value; 31 | 32 | $parameterBag->remove($name); 33 | $container->log($this, \sprintf('Removing build parameter "%s".', $name)); 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * @return array 40 | */ 41 | public function getRemovedParameters(): array 42 | { 43 | return $this->removedParameters; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Compiler/RemovePrivateAliasesPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * Remove private aliases from the container. They were only used to establish 18 | * dependencies between services, and these dependencies have been resolved in 19 | * one of the previous passes. 20 | * 21 | * @author Johannes M. Schmitt 22 | */ 23 | class RemovePrivateAliasesPass implements CompilerPassInterface 24 | { 25 | /** 26 | * Removes private aliases from the ContainerBuilder. 27 | */ 28 | public function process(ContainerBuilder $container): void 29 | { 30 | foreach ($container->getAliases() as $id => $alias) { 31 | if ($alias->isPublic()) { 32 | continue; 33 | } 34 | 35 | $container->removeAlias($id); 36 | $container->log($this, \sprintf('Removed service "%s"; reason: private alias.', $id)); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Compiler/RemoveUnusedDefinitionsPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Reference; 16 | 17 | /** 18 | * Removes unused service definitions from the container. 19 | * 20 | * @author Johannes M. Schmitt 21 | * @author Nicolas Grekas 22 | */ 23 | class RemoveUnusedDefinitionsPass extends AbstractRecursivePass 24 | { 25 | protected bool $skipScalars = true; 26 | 27 | private array $connectedIds = []; 28 | 29 | /** 30 | * Processes the ContainerBuilder to remove unused definitions. 31 | */ 32 | public function process(ContainerBuilder $container): void 33 | { 34 | try { 35 | $this->enableExpressionProcessing(); 36 | $this->container = $container; 37 | $connectedIds = []; 38 | $aliases = $container->getAliases(); 39 | 40 | foreach ($aliases as $id => $alias) { 41 | if ($alias->isPublic()) { 42 | $this->connectedIds[] = (string) $aliases[$id]; 43 | } 44 | } 45 | 46 | foreach ($container->getDefinitions() as $id => $definition) { 47 | if ($definition->isPublic()) { 48 | $connectedIds[$id] = true; 49 | $this->processValue($definition); 50 | } 51 | } 52 | 53 | while ($this->connectedIds) { 54 | $ids = $this->connectedIds; 55 | $this->connectedIds = []; 56 | foreach ($ids as $id) { 57 | if (!isset($connectedIds[$id]) && $container->hasDefinition($id)) { 58 | $connectedIds[$id] = true; 59 | $this->processValue($container->getDefinition($id)); 60 | } 61 | } 62 | } 63 | 64 | foreach ($container->getDefinitions() as $id => $definition) { 65 | if (!isset($connectedIds[$id])) { 66 | $container->removeDefinition($id); 67 | $container->resolveEnvPlaceholders(!$definition->hasErrors() ? serialize($definition) : $definition); 68 | $container->log($this, \sprintf('Removed service "%s"; reason: unused.', $id)); 69 | } 70 | } 71 | } finally { 72 | $this->container = null; 73 | $this->connectedIds = []; 74 | } 75 | } 76 | 77 | protected function processValue(mixed $value, bool $isRoot = false): mixed 78 | { 79 | if (!$value instanceof Reference) { 80 | return parent::processValue($value, $isRoot); 81 | } 82 | 83 | if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) { 84 | $this->connectedIds[] = (string) $value; 85 | } 86 | 87 | return $value; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Compiler/ResolveClassPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ChildDefinition; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 17 | 18 | /** 19 | * @author Nicolas Grekas 20 | */ 21 | class ResolveClassPass implements CompilerPassInterface 22 | { 23 | public function process(ContainerBuilder $container): void 24 | { 25 | foreach ($container->getDefinitions() as $id => $definition) { 26 | if ($definition->isSynthetic() || null !== $definition->getClass()) { 27 | continue; 28 | } 29 | 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)) { 30 | if ($definition instanceof ChildDefinition && !class_exists($id)) { 31 | 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)); 32 | } 33 | $definition->setClass($id); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Compiler/ResolveEnvPlaceholdersPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * Replaces env var placeholders by their current values. 18 | */ 19 | class ResolveEnvPlaceholdersPass extends AbstractRecursivePass 20 | { 21 | protected bool $skipScalars = false; 22 | 23 | protected function processValue(mixed $value, bool $isRoot = false): mixed 24 | { 25 | if (\is_string($value)) { 26 | return $this->container->resolveEnvPlaceholders($value, true); 27 | } 28 | if ($value instanceof Definition) { 29 | $changes = $value->getChanges(); 30 | if (isset($changes['class'])) { 31 | $value->setClass($this->container->resolveEnvPlaceholders($value->getClass(), true)); 32 | } 33 | if (isset($changes['file'])) { 34 | $value->setFile($this->container->resolveEnvPlaceholders($value->getFile(), true)); 35 | } 36 | } 37 | 38 | $value = parent::processValue($value, $isRoot); 39 | 40 | if ($value && \is_array($value) && !$isRoot) { 41 | $value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), true), $value); 42 | } 43 | 44 | return $value; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Compiler/ResolveFactoryClassPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Exception\RuntimeException; 16 | 17 | /** 18 | * @author Maxime Steinhausser 19 | */ 20 | class ResolveFactoryClassPass extends AbstractRecursivePass 21 | { 22 | protected bool $skipScalars = true; 23 | 24 | protected function processValue(mixed $value, bool $isRoot = false): mixed 25 | { 26 | if ($value instanceof Definition && \is_array($factory = $value->getFactory()) && null === $factory[0]) { 27 | if (null === $class = $value->getClass()) { 28 | 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)); 29 | } 30 | 31 | $factory[0] = $class; 32 | $value->setFactory($factory); 33 | } 34 | 35 | return parent::processValue($value, $isRoot); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Compiler/ResolveHotPathPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Definition; 17 | use Symfony\Component\DependencyInjection\Reference; 18 | 19 | /** 20 | * Propagate "container.hot_path" tags to referenced services. 21 | * 22 | * @author Nicolas Grekas 23 | */ 24 | class ResolveHotPathPass extends AbstractRecursivePass 25 | { 26 | protected bool $skipScalars = true; 27 | 28 | private array $resolvedIds = []; 29 | 30 | public function process(ContainerBuilder $container): void 31 | { 32 | try { 33 | parent::process($container); 34 | $container->getDefinition('service_container')->clearTag('container.hot_path'); 35 | } finally { 36 | $this->resolvedIds = []; 37 | } 38 | } 39 | 40 | protected function processValue(mixed $value, bool $isRoot = false): mixed 41 | { 42 | if ($value instanceof ArgumentInterface) { 43 | return $value; 44 | } 45 | 46 | if ($value instanceof Definition && $isRoot) { 47 | if ($value->isDeprecated()) { 48 | return $value->clearTag('container.hot_path'); 49 | } 50 | 51 | $this->resolvedIds[$this->currentId] = true; 52 | 53 | if (!$value->hasTag('container.hot_path')) { 54 | return $value; 55 | } 56 | } 57 | 58 | if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->hasDefinition($id = (string) $value)) { 59 | $definition = $this->container->getDefinition($id); 60 | 61 | if ($definition->isDeprecated() || $definition->hasTag('container.hot_path')) { 62 | return $value; 63 | } 64 | 65 | $definition->addTag('container.hot_path'); 66 | 67 | if (isset($this->resolvedIds[$id])) { 68 | parent::processValue($definition, false); 69 | } 70 | 71 | return $value; 72 | } 73 | 74 | return parent::processValue($value, $isRoot); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Compiler/ResolveNoPreloadPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | 18 | /** 19 | * Propagate the "container.no_preload" tag. 20 | * 21 | * @author Nicolas Grekas 22 | */ 23 | class ResolveNoPreloadPass extends AbstractRecursivePass 24 | { 25 | private const DO_PRELOAD_TAG = '.container.do_preload'; 26 | 27 | protected bool $skipScalars = true; 28 | 29 | private array $resolvedIds = []; 30 | 31 | public function process(ContainerBuilder $container): void 32 | { 33 | $this->container = $container; 34 | 35 | try { 36 | foreach ($container->getDefinitions() as $id => $definition) { 37 | if ($definition->isPublic() && !$definition->isPrivate() && !isset($this->resolvedIds[$id])) { 38 | $this->resolvedIds[$id] = true; 39 | $this->processValue($definition, true); 40 | } 41 | } 42 | 43 | foreach ($container->getAliases() as $alias) { 44 | if ($alias->isPublic() && !$alias->isPrivate() && !isset($this->resolvedIds[$id = (string) $alias]) && $container->hasDefinition($id)) { 45 | $this->resolvedIds[$id] = true; 46 | $this->processValue($container->getDefinition($id), true); 47 | } 48 | } 49 | } finally { 50 | $this->resolvedIds = []; 51 | $this->container = null; 52 | } 53 | 54 | foreach ($container->getDefinitions() as $definition) { 55 | if ($definition->hasTag(self::DO_PRELOAD_TAG)) { 56 | $definition->clearTag(self::DO_PRELOAD_TAG); 57 | } elseif (!$definition->isDeprecated() && !$definition->hasErrors()) { 58 | $definition->addTag('container.no_preload'); 59 | } 60 | } 61 | } 62 | 63 | protected function processValue(mixed $value, bool $isRoot = false): mixed 64 | { 65 | if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->hasDefinition($id = (string) $value)) { 66 | $definition = $this->container->getDefinition($id); 67 | 68 | if (!isset($this->resolvedIds[$id]) && (!$definition->isPublic() || $definition->isPrivate())) { 69 | $this->resolvedIds[$id] = true; 70 | $this->processValue($definition, true); 71 | } 72 | 73 | return $value; 74 | } 75 | 76 | if (!$value instanceof Definition) { 77 | return parent::processValue($value, $isRoot); 78 | } 79 | 80 | if ($value->hasTag('container.no_preload') || $value->isDeprecated() || $value->hasErrors()) { 81 | return $value; 82 | } 83 | 84 | if ($isRoot) { 85 | $value->addTag(self::DO_PRELOAD_TAG); 86 | } 87 | 88 | return parent::processValue($value, $isRoot); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Compiler/ResolveReferencesToAliasesPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | 18 | /** 19 | * Replaces all references to aliases with references to the actual service. 20 | * 21 | * @author Johannes M. Schmitt 22 | */ 23 | class ResolveReferencesToAliasesPass extends AbstractRecursivePass 24 | { 25 | protected bool $skipScalars = true; 26 | 27 | public function process(ContainerBuilder $container): void 28 | { 29 | parent::process($container); 30 | 31 | foreach ($container->getAliases() as $id => $alias) { 32 | $aliasId = (string) $alias; 33 | $this->currentId = $id; 34 | 35 | if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) { 36 | $container->setAlias($id, $defId)->setPublic($alias->isPublic()); 37 | } 38 | } 39 | } 40 | 41 | protected function processValue(mixed $value, bool $isRoot = false): mixed 42 | { 43 | if (!$value instanceof Reference) { 44 | return parent::processValue($value, $isRoot); 45 | } 46 | 47 | $defId = $this->getDefinitionId($id = (string) $value, $this->container); 48 | 49 | return $defId !== $id ? new Reference($defId, $value->getInvalidBehavior()) : $value; 50 | } 51 | 52 | private function getDefinitionId(string $id, ContainerBuilder $container): string 53 | { 54 | if (!$container->hasAlias($id)) { 55 | return $id; 56 | } 57 | 58 | $alias = $container->getAlias($id); 59 | 60 | if ($alias->isDeprecated()) { 61 | $referencingDefinition = $container->hasDefinition($this->currentId) ? $container->getDefinition($this->currentId) : $container->getAlias($this->currentId); 62 | if (!$referencingDefinition->isDeprecated()) { 63 | $deprecation = $alias->getDeprecation($id); 64 | trigger_deprecation($deprecation['package'], $deprecation['version'], rtrim($deprecation['message'], '. ').'. It is being referenced by the "%s" '.($container->hasDefinition($this->currentId) ? 'service.' : 'alias.'), $this->currentId); 65 | } 66 | } 67 | 68 | $seen = []; 69 | do { 70 | if (isset($seen[$id])) { 71 | throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id])); 72 | } 73 | 74 | $seen[$id] = true; 75 | $id = (string) $container->getAlias($id); 76 | } while ($container->hasAlias($id)); 77 | 78 | return $id; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Compiler/ResolveServiceSubscribersPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Psr\Container\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | use Symfony\Component\DependencyInjection\Reference; 17 | use Symfony\Contracts\Service\ServiceProviderInterface; 18 | 19 | /** 20 | * Compiler pass to inject their service locator to service subscribers. 21 | * 22 | * @author Nicolas Grekas 23 | */ 24 | class ResolveServiceSubscribersPass extends AbstractRecursivePass 25 | { 26 | protected bool $skipScalars = true; 27 | 28 | private ?string $serviceLocator = null; 29 | 30 | protected function processValue(mixed $value, bool $isRoot = false): mixed 31 | { 32 | if ($value instanceof Reference && $this->serviceLocator && \in_array((string) $value, [ContainerInterface::class, ServiceProviderInterface::class], true)) { 33 | return new Reference($this->serviceLocator); 34 | } 35 | 36 | if (!$value instanceof Definition) { 37 | return parent::processValue($value, $isRoot); 38 | } 39 | 40 | $serviceLocator = $this->serviceLocator; 41 | $this->serviceLocator = null; 42 | 43 | if ($value->hasTag('container.service_subscriber.locator')) { 44 | $this->serviceLocator = $value->getTag('container.service_subscriber.locator')[0]['id']; 45 | $value->clearTag('container.service_subscriber.locator'); 46 | } 47 | 48 | try { 49 | return parent::processValue($value); 50 | } finally { 51 | $this->serviceLocator = $serviceLocator; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Compiler/ResolveTaggedIteratorArgumentPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; 15 | 16 | /** 17 | * Resolves all TaggedIteratorArgument arguments. 18 | * 19 | * @author Roland Franssen 20 | */ 21 | class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass 22 | { 23 | use PriorityTaggedServiceTrait; 24 | 25 | protected bool $skipScalars = true; 26 | 27 | protected function processValue(mixed $value, bool $isRoot = false): mixed 28 | { 29 | if (!$value instanceof TaggedIteratorArgument) { 30 | return parent::processValue($value, $isRoot); 31 | } 32 | 33 | $exclude = $value->getExclude(); 34 | if ($value->excludeSelf()) { 35 | $exclude[] = $this->currentId; 36 | } 37 | 38 | $value->setValues($this->findAndSortTaggedServices($value, $this->container, $exclude)); 39 | 40 | return $value; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Compiler/ServiceReferenceGraph.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | use Symfony\Component\DependencyInjection\Reference; 16 | 17 | /** 18 | * This is a directed graph of your services. 19 | * 20 | * This information can be used by your compiler passes instead of collecting 21 | * it themselves which improves performance quite a lot. 22 | * 23 | * @author Johannes M. Schmitt 24 | * 25 | * @final 26 | */ 27 | class ServiceReferenceGraph 28 | { 29 | /** 30 | * @var ServiceReferenceGraphNode[] 31 | */ 32 | private array $nodes = []; 33 | 34 | public function hasNode(string $id): bool 35 | { 36 | return isset($this->nodes[$id]); 37 | } 38 | 39 | /** 40 | * Gets a node by identifier. 41 | * 42 | * @throws InvalidArgumentException if no node matches the supplied identifier 43 | */ 44 | public function getNode(string $id): ServiceReferenceGraphNode 45 | { 46 | if (!isset($this->nodes[$id])) { 47 | throw new InvalidArgumentException(\sprintf('There is no node with id "%s".', $id)); 48 | } 49 | 50 | return $this->nodes[$id]; 51 | } 52 | 53 | /** 54 | * Returns all nodes. 55 | * 56 | * @return ServiceReferenceGraphNode[] 57 | */ 58 | public function getNodes(): array 59 | { 60 | return $this->nodes; 61 | } 62 | 63 | /** 64 | * Clears all nodes. 65 | */ 66 | public function clear(): void 67 | { 68 | foreach ($this->nodes as $node) { 69 | $node->clear(); 70 | } 71 | $this->nodes = []; 72 | } 73 | 74 | /** 75 | * Connects 2 nodes together in the Graph. 76 | */ 77 | 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 78 | { 79 | if (null === $sourceId || null === $destId) { 80 | return; 81 | } 82 | 83 | $sourceNode = $this->createNode($sourceId, $sourceValue); 84 | $destNode = $this->createNode($destId, $destValue); 85 | $edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak, $byConstructor); 86 | 87 | $sourceNode->addOutEdge($edge); 88 | $destNode->addInEdge($edge); 89 | } 90 | 91 | private function createNode(string $id, mixed $value): ServiceReferenceGraphNode 92 | { 93 | if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) { 94 | return $this->nodes[$id]; 95 | } 96 | 97 | return $this->nodes[$id] = new ServiceReferenceGraphNode($id, $value); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Compiler/ServiceReferenceGraphEdge.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | /** 15 | * Represents an edge in your service graph. 16 | * 17 | * Value is typically a reference. 18 | * 19 | * @author Johannes M. Schmitt 20 | */ 21 | class ServiceReferenceGraphEdge 22 | { 23 | public function __construct( 24 | private ServiceReferenceGraphNode $sourceNode, 25 | private ServiceReferenceGraphNode $destNode, 26 | private mixed $value = null, 27 | private bool $lazy = false, 28 | private bool $weak = false, 29 | private bool $byConstructor = false, 30 | ) { 31 | } 32 | 33 | /** 34 | * Returns the value of the edge. 35 | */ 36 | public function getValue(): mixed 37 | { 38 | return $this->value; 39 | } 40 | 41 | /** 42 | * Returns the source node. 43 | */ 44 | public function getSourceNode(): ServiceReferenceGraphNode 45 | { 46 | return $this->sourceNode; 47 | } 48 | 49 | /** 50 | * Returns the destination node. 51 | */ 52 | public function getDestNode(): ServiceReferenceGraphNode 53 | { 54 | return $this->destNode; 55 | } 56 | 57 | /** 58 | * Returns true if the edge is lazy, meaning it's a dependency not requiring direct instantiation. 59 | */ 60 | public function isLazy(): bool 61 | { 62 | return $this->lazy; 63 | } 64 | 65 | /** 66 | * Returns true if the edge is weak, meaning it shouldn't prevent removing the target service. 67 | */ 68 | public function isWeak(): bool 69 | { 70 | return $this->weak; 71 | } 72 | 73 | /** 74 | * Returns true if the edge links with a constructor argument. 75 | */ 76 | public function isReferencedByConstructor(): bool 77 | { 78 | return $this->byConstructor; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Compiler/ServiceReferenceGraphNode.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Alias; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | 17 | /** 18 | * Represents a node in your service graph. 19 | * 20 | * Value is typically a definition, or an alias. 21 | * 22 | * @author Johannes M. Schmitt 23 | */ 24 | class ServiceReferenceGraphNode 25 | { 26 | private array $inEdges = []; 27 | private array $outEdges = []; 28 | 29 | public function __construct( 30 | private string $id, 31 | private mixed $value, 32 | ) { 33 | } 34 | 35 | public function addInEdge(ServiceReferenceGraphEdge $edge): void 36 | { 37 | $this->inEdges[] = $edge; 38 | } 39 | 40 | public function addOutEdge(ServiceReferenceGraphEdge $edge): void 41 | { 42 | $this->outEdges[] = $edge; 43 | } 44 | 45 | /** 46 | * Checks if the value of this node is an Alias. 47 | */ 48 | public function isAlias(): bool 49 | { 50 | return $this->value instanceof Alias; 51 | } 52 | 53 | /** 54 | * Checks if the value of this node is a Definition. 55 | */ 56 | public function isDefinition(): bool 57 | { 58 | return $this->value instanceof Definition; 59 | } 60 | 61 | /** 62 | * Returns the identifier. 63 | */ 64 | public function getId(): string 65 | { 66 | return $this->id; 67 | } 68 | 69 | /** 70 | * Returns the in edges. 71 | * 72 | * @return ServiceReferenceGraphEdge[] 73 | */ 74 | public function getInEdges(): array 75 | { 76 | return $this->inEdges; 77 | } 78 | 79 | /** 80 | * Returns the out edges. 81 | * 82 | * @return ServiceReferenceGraphEdge[] 83 | */ 84 | public function getOutEdges(): array 85 | { 86 | return $this->outEdges; 87 | } 88 | 89 | /** 90 | * Returns the value of this Node. 91 | */ 92 | public function getValue(): mixed 93 | { 94 | return $this->value; 95 | } 96 | 97 | /** 98 | * Clears all edges. 99 | */ 100 | public function clear(): void 101 | { 102 | $this->inEdges = $this->outEdges = []; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Config/ContainerParametersResource.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Config; 13 | 14 | use Symfony\Component\Config\Resource\ResourceInterface; 15 | 16 | /** 17 | * Tracks container parameters. 18 | * 19 | * @author Maxime Steinhausser 20 | * 21 | * @final 22 | */ 23 | class ContainerParametersResource implements ResourceInterface 24 | { 25 | /** 26 | * @param array $parameters The container parameters to track 27 | */ 28 | public function __construct( 29 | private array $parameters, 30 | ) { 31 | } 32 | 33 | public function __toString(): string 34 | { 35 | return 'container_parameters_'.hash('xxh128', serialize($this->parameters)); 36 | } 37 | 38 | public function getParameters(): array 39 | { 40 | return $this->parameters; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Config/ContainerParametersResourceChecker.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Config; 13 | 14 | use Symfony\Component\Config\Resource\ResourceInterface; 15 | use Symfony\Component\Config\ResourceCheckerInterface; 16 | use Symfony\Component\DependencyInjection\ContainerInterface; 17 | 18 | /** 19 | * @author Maxime Steinhausser 20 | */ 21 | class ContainerParametersResourceChecker implements ResourceCheckerInterface 22 | { 23 | public function __construct( 24 | private ContainerInterface $container, 25 | ) { 26 | } 27 | 28 | public function supports(ResourceInterface $metadata): bool 29 | { 30 | return $metadata instanceof ContainerParametersResource; 31 | } 32 | 33 | public function isFresh(ResourceInterface $resource, int $timestamp): bool 34 | { 35 | foreach ($resource->getParameters() as $key => $value) { 36 | if (!$this->container->hasParameter($key) || $this->container->getParameter($key) !== $value) { 37 | return false; 38 | } 39 | } 40 | 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ContainerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Psr\Container\ContainerInterface as PsrContainerInterface; 15 | use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; 16 | use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; 17 | use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 18 | 19 | /** 20 | * ContainerInterface is the interface implemented by service container classes. 21 | * 22 | * @author Fabien Potencier 23 | * @author Johannes M. Schmitt 24 | */ 25 | interface ContainerInterface extends PsrContainerInterface 26 | { 27 | public const RUNTIME_EXCEPTION_ON_INVALID_REFERENCE = 0; 28 | public const EXCEPTION_ON_INVALID_REFERENCE = 1; 29 | public const NULL_ON_INVALID_REFERENCE = 2; 30 | public const IGNORE_ON_INVALID_REFERENCE = 3; 31 | public const IGNORE_ON_UNINITIALIZED_REFERENCE = 4; 32 | 33 | public function set(string $id, ?object $service): void; 34 | 35 | /** 36 | * @template C of object 37 | * @template B of self::*_REFERENCE 38 | * 39 | * @param string|class-string $id 40 | * @param B $invalidBehavior 41 | * 42 | * @return ($id is class-string ? (B is 0|1 ? C|object : C|object|null) : (B is 0|1 ? object : object|null)) 43 | * 44 | * @throws ServiceCircularReferenceException When a circular reference is detected 45 | * @throws ServiceNotFoundException When the service is not defined 46 | * 47 | * @see Reference 48 | */ 49 | public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE): ?object; 50 | 51 | public function has(string $id): bool; 52 | 53 | /** 54 | * Check for whether or not a service has been initialized. 55 | */ 56 | public function initialized(string $id): bool; 57 | 58 | /** 59 | * @throws ParameterNotFoundException if the parameter is not defined 60 | */ 61 | public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null; 62 | 63 | public function hasParameter(string $name): bool; 64 | 65 | public function setParameter(string $name, array|bool|string|int|float|\UnitEnum|null $value): void; 66 | } 67 | -------------------------------------------------------------------------------- /Dumper/Dumper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Dumper; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * Dumper is the abstract class for all built-in dumpers. 18 | * 19 | * @author Fabien Potencier 20 | */ 21 | abstract class Dumper implements DumperInterface 22 | { 23 | public function __construct( 24 | protected ContainerBuilder $container, 25 | ) { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Dumper/DumperInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Dumper; 13 | 14 | /** 15 | * DumperInterface is the interface implemented by service container dumper classes. 16 | * 17 | * @author Fabien Potencier 18 | */ 19 | interface DumperInterface 20 | { 21 | /** 22 | * Dumps the service container. 23 | */ 24 | public function dump(array $options = []): string|array; 25 | } 26 | -------------------------------------------------------------------------------- /EnvVarLoaderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * EnvVarLoaderInterface objects return key/value pairs that are added to the list of available env vars. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | interface EnvVarLoaderInterface 20 | { 21 | /** 22 | * @return array Key/value pairs that can be accessed using the regular "%env()%" syntax 23 | */ 24 | public function loadEnvVars(): array; 25 | } 26 | -------------------------------------------------------------------------------- /EnvVarProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\RuntimeException; 15 | 16 | /** 17 | * The EnvVarProcessorInterface is implemented by objects that manage environment-like variables. 18 | * 19 | * @author Nicolas Grekas 20 | */ 21 | interface EnvVarProcessorInterface 22 | { 23 | /** 24 | * Returns the value of the given variable as managed by the current instance. 25 | * 26 | * @param string $prefix The namespace of the variable; when the empty string is passed, null values should be kept as is 27 | * @param string $name The name of the variable within the namespace 28 | * @param \Closure(string): mixed $getEnv A closure that allows fetching more env vars 29 | * 30 | * @throws RuntimeException on error 31 | */ 32 | public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed; 33 | 34 | /** 35 | * @return array The PHP-types managed by getEnv(), keyed by prefixes 36 | */ 37 | public static function getProvidedTypes(): array; 38 | } 39 | -------------------------------------------------------------------------------- /Exception/AutoconfigureFailedException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | class AutoconfigureFailedException extends AutowiringFailedException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /Exception/AutowiringFailedException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Thrown when a definition cannot be autowired. 16 | */ 17 | class AutowiringFailedException extends RuntimeException 18 | { 19 | private ?\Closure $messageCallback = null; 20 | 21 | public function __construct( 22 | private string $serviceId, 23 | string|\Closure $message = '', 24 | int $code = 0, 25 | ?\Throwable $previous = null, 26 | ) { 27 | if ($message instanceof \Closure && \function_exists('xdebug_is_enabled') && xdebug_is_enabled()) { 28 | $message = $message(); 29 | } 30 | 31 | if (!$message instanceof \Closure) { 32 | parent::__construct($message, $code, $previous); 33 | 34 | return; 35 | } 36 | 37 | $this->messageCallback = $message; 38 | parent::__construct('', $code, $previous); 39 | 40 | $this->message = new class($this->message, $this->messageCallback) { 41 | private string|self $message; 42 | private ?\Closure $messageCallback; 43 | 44 | public function __construct(&$message, &$messageCallback) 45 | { 46 | $this->message = &$message; 47 | $this->messageCallback = &$messageCallback; 48 | } 49 | 50 | public function __toString(): string 51 | { 52 | $messageCallback = $this->messageCallback; 53 | $this->messageCallback = null; 54 | 55 | try { 56 | return $this->message = $messageCallback(); 57 | } catch (\Throwable $e) { 58 | return $this->message = $e->getMessage(); 59 | } 60 | } 61 | }; 62 | } 63 | 64 | public function getMessageCallback(): ?\Closure 65 | { 66 | return $this->messageCallback; 67 | } 68 | 69 | public function getServiceId(): string 70 | { 71 | return $this->serviceId; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Exception/BadMethodCallException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Base BadMethodCallException for Dependency Injection component. 16 | */ 17 | class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/EmptyParameterValueException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | use Psr\Container\NotFoundExceptionInterface; 15 | 16 | /** 17 | * This exception is thrown when an existent parameter with an empty value is used. 18 | * 19 | * @author Yonel Ceruto 20 | */ 21 | class EmptyParameterValueException extends InvalidArgumentException implements NotFoundExceptionInterface 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /Exception/EnvNotFoundException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * This exception is thrown when an environment variable is not found. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | class EnvNotFoundException extends InvalidArgumentException 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /Exception/EnvParameterException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * This exception wraps exceptions whose messages contain a reference to an env parameter. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | class EnvParameterException extends InvalidArgumentException 20 | { 21 | public function __construct(array $envs, ?\Throwable $previous = null, string $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.') 22 | { 23 | parent::__construct(\sprintf($message, implode('", "', $envs)), 0, $previous); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | use Psr\Container\ContainerExceptionInterface; 15 | 16 | /** 17 | * Base ExceptionInterface for Dependency Injection component. 18 | * 19 | * @author Fabien Potencier 20 | * @author Bulat Shakirzyanov 21 | */ 22 | interface ExceptionInterface extends ContainerExceptionInterface, \Throwable 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Base InvalidArgumentException for Dependency Injection component. 16 | * 17 | * @author Bulat Shakirzyanov 18 | */ 19 | class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /Exception/InvalidParameterTypeException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Thrown when trying to inject a parameter into a constructor/method with an incompatible type. 16 | * 17 | * @author Nicolas Grekas 18 | * @author Julien Maulny 19 | */ 20 | class InvalidParameterTypeException extends InvalidArgumentException 21 | { 22 | public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter) 23 | { 24 | $acceptedType = $parameter->getType(); 25 | $acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType; 26 | $this->code = $type; 27 | 28 | $function = $parameter->getDeclaringFunction(); 29 | $functionName = $function instanceof \ReflectionMethod 30 | ? \sprintf('%s::%s', $function->getDeclaringClass()->getName(), $function->getName()) 31 | : $function->getName(); 32 | 33 | parent::__construct(\sprintf('Invalid definition for service "%s": argument %d of "%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $functionName, $acceptedType, $type)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Exception/LogicException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Base LogicException for Dependency Injection component. 16 | */ 17 | class LogicException extends \LogicException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/OutOfBoundsException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Base OutOfBoundsException for Dependency Injection component. 16 | */ 17 | class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/ParameterCircularReferenceException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * This exception is thrown when a circular reference in a parameter is detected. 16 | * 17 | * @author Fabien Potencier 18 | */ 19 | class ParameterCircularReferenceException extends RuntimeException 20 | { 21 | public function __construct( 22 | private array $parameters, 23 | ?\Throwable $previous = null, 24 | ) { 25 | parent::__construct(\sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]), 0, $previous); 26 | } 27 | 28 | public function getParameters(): array 29 | { 30 | return $this->parameters; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Exception/RuntimeException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * Base RuntimeException for Dependency Injection component. 16 | * 17 | * @author Johannes M. Schmitt 18 | */ 19 | class RuntimeException extends \RuntimeException implements ExceptionInterface 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /Exception/ServiceCircularReferenceException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | /** 15 | * This exception is thrown when a circular reference is detected. 16 | * 17 | * @author Johannes M. Schmitt 18 | */ 19 | class ServiceCircularReferenceException extends RuntimeException 20 | { 21 | public function __construct( 22 | private string $serviceId, 23 | private array $path, 24 | ?\Throwable $previous = null, 25 | ) { 26 | parent::__construct(\sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)), 0, $previous); 27 | } 28 | 29 | public function getServiceId(): string 30 | { 31 | return $this->serviceId; 32 | } 33 | 34 | public function getPath(): array 35 | { 36 | return $this->path; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Exception/ServiceNotFoundException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Exception; 13 | 14 | use Psr\Container\NotFoundExceptionInterface; 15 | 16 | /** 17 | * This exception is thrown when a non-existent service is requested. 18 | * 19 | * @author Johannes M. Schmitt 20 | */ 21 | class ServiceNotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface 22 | { 23 | public function __construct( 24 | private string $id, 25 | private ?string $sourceId = null, 26 | ?\Throwable $previous = null, 27 | private array $alternatives = [], 28 | ?string $msg = null, 29 | ) { 30 | if (null !== $msg) { 31 | // no-op 32 | } elseif (null === $sourceId) { 33 | $msg = \sprintf('You have requested a non-existent service "%s".', $id); 34 | } else { 35 | $msg = \sprintf('The service "%s" has a dependency on a non-existent service "%s".', $sourceId, $id); 36 | } 37 | 38 | if ($alternatives) { 39 | if (1 == \count($alternatives)) { 40 | $msg .= ' Did you mean this: "'; 41 | } else { 42 | $msg .= ' Did you mean one of these: "'; 43 | } 44 | $msg .= implode('", "', $alternatives).'"?'; 45 | } 46 | 47 | parent::__construct($msg, 0, $previous); 48 | } 49 | 50 | public function getId(): string 51 | { 52 | return $this->id; 53 | } 54 | 55 | public function getSourceId(): ?string 56 | { 57 | return $this->sourceId; 58 | } 59 | 60 | public function getAlternatives(): array 61 | { 62 | return $this->alternatives; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ExpressionLanguage.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Psr\Cache\CacheItemPoolInterface; 15 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage; 16 | 17 | if (!class_exists(BaseExpressionLanguage::class)) { 18 | return; 19 | } 20 | 21 | /** 22 | * Adds some function to the default ExpressionLanguage. 23 | * 24 | * @author Fabien Potencier 25 | * 26 | * @see ExpressionLanguageProvider 27 | */ 28 | class ExpressionLanguage extends BaseExpressionLanguage 29 | { 30 | public function __construct(?CacheItemPoolInterface $cache = null, iterable $providers = [], ?callable $serviceCompiler = null, ?\Closure $getEnv = null) 31 | { 32 | if (!\is_array($providers)) { 33 | $providers = iterator_to_array($providers, false); 34 | } 35 | 36 | // prepend the default provider to let users override it easily 37 | array_unshift($providers, new ExpressionLanguageProvider($serviceCompiler, $getEnv)); 38 | 39 | parent::__construct($cache, $providers); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ExpressionLanguageProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\LogicException; 15 | use Symfony\Component\ExpressionLanguage\ExpressionFunction; 16 | use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; 17 | 18 | /** 19 | * Define some ExpressionLanguage functions. 20 | * 21 | * To get a service, use service('request'). 22 | * To get a parameter, use parameter('kernel.debug'). 23 | * To get an env variable, use env('SOME_VARIABLE'). 24 | * 25 | * @author Fabien Potencier 26 | */ 27 | class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface 28 | { 29 | private ?\Closure $serviceCompiler; 30 | 31 | public function __construct( 32 | ?callable $serviceCompiler = null, 33 | private ?\Closure $getEnv = null, 34 | ) { 35 | $this->serviceCompiler = null === $serviceCompiler ? null : $serviceCompiler(...); 36 | } 37 | 38 | public function getFunctions(): array 39 | { 40 | return [ 41 | new ExpressionFunction('service', $this->serviceCompiler ?? fn ($arg) => \sprintf('$container->get(%s)', $arg), fn (array $variables, $value) => $variables['container']->get($value)), 42 | 43 | new ExpressionFunction('parameter', fn ($arg) => \sprintf('$container->getParameter(%s)', $arg), fn (array $variables, $value) => $variables['container']->getParameter($value)), 44 | 45 | new ExpressionFunction('env', fn ($arg) => \sprintf('$container->getEnv(%s)', $arg), function (array $variables, $value) { 46 | if (!$this->getEnv) { 47 | throw new LogicException('You need to pass a getEnv closure to the expression language provider to use the "env" function.'); 48 | } 49 | 50 | return ($this->getEnv)($value); 51 | }), 52 | 53 | new ExpressionFunction('arg', fn ($arg) => \sprintf('$args?->get(%s)', $arg), fn (array $variables, $value) => $variables['args']?->get($value)), 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Extension/AbstractExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\Config\Definition\Configuration; 15 | use Symfony\Component\Config\Definition\ConfigurationInterface; 16 | use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; 19 | 20 | /** 21 | * An Extension that provides configuration hooks. 22 | * 23 | * @author Yonel Ceruto 24 | */ 25 | abstract class AbstractExtension extends Extension implements ConfigurableExtensionInterface, PrependExtensionInterface 26 | { 27 | use ExtensionTrait; 28 | 29 | public function configure(DefinitionConfigurator $definition): void 30 | { 31 | } 32 | 33 | public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void 34 | { 35 | } 36 | 37 | public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void 38 | { 39 | } 40 | 41 | public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface 42 | { 43 | return new Configuration($this, $container, $this->getAlias()); 44 | } 45 | 46 | final public function prepend(ContainerBuilder $container): void 47 | { 48 | $callback = function (ContainerConfigurator $configurator) use ($container) { 49 | $this->prependExtension($configurator, $container); 50 | }; 51 | 52 | $this->executeConfiguratorCallback($container, $callback, $this, true); 53 | } 54 | 55 | final public function load(array $configs, ContainerBuilder $container): void 56 | { 57 | $config = $this->processConfiguration($this->getConfiguration([], $container), $configs); 58 | 59 | $callback = function (ContainerConfigurator $configurator) use ($config, $container) { 60 | $this->loadExtension($config, $configurator, $container); 61 | }; 62 | 63 | $this->executeConfiguratorCallback($container, $callback, $this); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Extension/ConfigurableExtensionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\Config\Definition\ConfigurableInterface; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; 17 | 18 | /** 19 | * @author Yonel Ceruto 20 | */ 21 | interface ConfigurableExtensionInterface extends ConfigurableInterface 22 | { 23 | /** 24 | * Allows an extension to prepend the extension configurations. 25 | */ 26 | public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void; 27 | 28 | /** 29 | * Loads a specific configuration. 30 | */ 31 | public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void; 32 | } 33 | -------------------------------------------------------------------------------- /Extension/ConfigurationExtensionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\Config\Definition\ConfigurationInterface; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | 17 | /** 18 | * ConfigurationExtensionInterface is the interface implemented by container extension classes. 19 | * 20 | * @author Kevin Bond 21 | */ 22 | interface ConfigurationExtensionInterface 23 | { 24 | /** 25 | * Returns extension configuration. 26 | * 27 | * @return ConfigurationInterface|null 28 | */ 29 | public function getConfiguration(array $config, ContainerBuilder $container); 30 | } 31 | -------------------------------------------------------------------------------- /Extension/ExtensionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | /** 17 | * ExtensionInterface is the interface implemented by container extension classes. 18 | * 19 | * @author Fabien Potencier 20 | */ 21 | interface ExtensionInterface 22 | { 23 | /** 24 | * Loads a specific configuration. 25 | * 26 | * @param array> $configs 27 | * 28 | * @return void 29 | * 30 | * @throws \InvalidArgumentException When provided tag is not defined in this extension 31 | */ 32 | public function load(array $configs, ContainerBuilder $container); 33 | 34 | /** 35 | * Returns the namespace to be used for this extension (XML namespace). 36 | * 37 | * @return string 38 | */ 39 | public function getNamespace(); 40 | 41 | /** 42 | * Returns the base path for the XSD files. 43 | * 44 | * @return string|false 45 | */ 46 | public function getXsdValidationBasePath(); 47 | 48 | /** 49 | * Returns the recommended alias to use in XML. 50 | * 51 | * This alias is also the mandatory prefix to use when using YAML. 52 | * 53 | * @return string 54 | */ 55 | public function getAlias(); 56 | } 57 | -------------------------------------------------------------------------------- /Extension/ExtensionTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\Config\Builder\ConfigBuilderGenerator; 15 | use Symfony\Component\Config\FileLocator; 16 | use Symfony\Component\Config\Loader\DelegatingLoader; 17 | use Symfony\Component\Config\Loader\LoaderResolver; 18 | use Symfony\Component\DependencyInjection\ContainerBuilder; 19 | use Symfony\Component\DependencyInjection\Loader\ClosureLoader; 20 | use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; 21 | use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; 22 | use Symfony\Component\DependencyInjection\Loader\GlobFileLoader; 23 | use Symfony\Component\DependencyInjection\Loader\IniFileLoader; 24 | use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; 25 | use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; 26 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 27 | 28 | /** 29 | * @author Yonel Ceruto 30 | */ 31 | trait ExtensionTrait 32 | { 33 | private function executeConfiguratorCallback(ContainerBuilder $container, \Closure $callback, ConfigurableExtensionInterface $subject, bool $prepend = false): void 34 | { 35 | $env = $container->getParameter('kernel.environment'); 36 | $loader = $this->createContainerLoader($container, $env, $prepend); 37 | $file = (new \ReflectionObject($subject))->getFileName(); 38 | $bundleLoader = $loader->getResolver()->resolve($file); 39 | if (!$bundleLoader instanceof PhpFileLoader) { 40 | throw new \LogicException('Unable to create the ContainerConfigurator.'); 41 | } 42 | $bundleLoader->setCurrentDir(\dirname($file)); 43 | $instanceof = &\Closure::bind(fn &() => $this->instanceof, $bundleLoader, $bundleLoader)(); 44 | 45 | try { 46 | $callback(new ContainerConfigurator($container, $bundleLoader, $instanceof, $file, $file, $env)); 47 | } finally { 48 | $instanceof = []; 49 | $bundleLoader->registerAliasesForSinglyImplementedInterfaces(); 50 | } 51 | } 52 | 53 | private function createContainerLoader(ContainerBuilder $container, string $env, bool $prepend): DelegatingLoader 54 | { 55 | $buildDir = $container->getParameter('kernel.build_dir'); 56 | $locator = new FileLocator(); 57 | $resolver = new LoaderResolver([ 58 | new XmlFileLoader($container, $locator, $env, $prepend), 59 | new YamlFileLoader($container, $locator, $env, $prepend), 60 | new IniFileLoader($container, $locator, $env), 61 | new PhpFileLoader($container, $locator, $env, new ConfigBuilderGenerator($buildDir), $prepend), 62 | new GlobFileLoader($container, $locator, $env), 63 | new DirectoryLoader($container, $locator, $env), 64 | new ClosureLoader($container, $env), 65 | ]); 66 | 67 | return new DelegatingLoader($resolver); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Extension/PrependExtensionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | 16 | interface PrependExtensionInterface 17 | { 18 | /** 19 | * Allow an extension to prepend the extension configurations. 20 | * 21 | * @return void 22 | */ 23 | public function prepend(ContainerBuilder $container); 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-present Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LazyProxy/Instantiator/InstantiatorInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | 17 | /** 18 | * Lazy proxy instantiator, capable of instantiating a proxy given a container, the 19 | * service definitions and a callback that produces the real service instance. 20 | * 21 | * @author Marco Pivetta 22 | */ 23 | interface InstantiatorInterface 24 | { 25 | /** 26 | * Instantiates a proxy object. 27 | * 28 | * @param string $id Identifier of the requested service 29 | * @param callable(object=) $realInstantiator A callback that is capable of producing the real service instance 30 | */ 31 | public function instantiateProxy(ContainerInterface $container, Definition $definition, string $id, callable $realInstantiator): object; 32 | } 33 | -------------------------------------------------------------------------------- /LazyProxy/Instantiator/LazyServiceInstantiator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 17 | use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper; 18 | 19 | /** 20 | * @author Nicolas Grekas 21 | */ 22 | final class LazyServiceInstantiator implements InstantiatorInterface 23 | { 24 | public function instantiateProxy(ContainerInterface $container, Definition $definition, string $id, callable $realInstantiator): object 25 | { 26 | $dumper = new LazyServiceDumper(); 27 | 28 | if (!$dumper->isProxyCandidate($definition, $asGhostObject, $id)) { 29 | throw new InvalidArgumentException(\sprintf('Cannot instantiate lazy proxy for service "%s".', $id)); 30 | } 31 | 32 | if (\PHP_VERSION_ID >= 80400 && $asGhostObject) { 33 | return (new \ReflectionClass($definition->getClass()))->newLazyGhost(static function ($ghost) use ($realInstantiator) { $realInstantiator($ghost); }); 34 | } 35 | 36 | $class = null; 37 | if (!class_exists($proxyClass = $dumper->getProxyClass($definition, $asGhostObject, $class), false)) { 38 | eval($dumper->getProxyCode($definition, $id)); 39 | } 40 | 41 | if ($definition->getClass() === $proxyClass) { 42 | return $class->newLazyProxy($realInstantiator); 43 | } 44 | 45 | return \PHP_VERSION_ID < 80400 && $asGhostObject ? $proxyClass::createLazyGhost($realInstantiator) : $proxyClass::createLazyProxy($realInstantiator); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LazyProxy/Instantiator/RealServiceInstantiator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | 17 | /** 18 | * Noop proxy instantiator - produces the real service instead of a proxy instance. 19 | * 20 | * @author Marco Pivetta 21 | */ 22 | class RealServiceInstantiator implements InstantiatorInterface 23 | { 24 | public function instantiateProxy(ContainerInterface $container, Definition $definition, string $id, callable $realInstantiator): object 25 | { 26 | return $realInstantiator(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LazyProxy/PhpDumper/DumperInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\LazyProxy\PhpDumper; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * Lazy proxy dumper capable of generating the instantiation logic PHP code for proxied services. 18 | * 19 | * @author Marco Pivetta 20 | */ 21 | interface DumperInterface 22 | { 23 | /** 24 | * Inspects whether the given definitions should produce proxy instantiation logic in the dumped container. 25 | * 26 | * @param bool|null &$asGhostObject Set to true after the call if the proxy is a ghost object 27 | */ 28 | public function isProxyCandidate(Definition $definition, ?bool &$asGhostObject = null, ?string $id = null): bool; 29 | 30 | /** 31 | * Generates the code to be used to instantiate a proxy in the dumped factory code. 32 | */ 33 | public function getProxyFactoryCode(Definition $definition, string $id, string $factoryCode): string; 34 | 35 | /** 36 | * Generates the code for the lazy proxy. 37 | */ 38 | public function getProxyCode(Definition $definition, ?string $id = null): string; 39 | } 40 | -------------------------------------------------------------------------------- /LazyProxy/PhpDumper/NullDumper.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\LazyProxy\PhpDumper; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * Null dumper, negates any proxy code generation for any given service definition. 18 | * 19 | * @author Marco Pivetta 20 | * 21 | * @final 22 | */ 23 | class NullDumper implements DumperInterface 24 | { 25 | public function isProxyCandidate(Definition $definition, ?bool &$asGhostObject = null, ?string $id = null): bool 26 | { 27 | return $asGhostObject = false; 28 | } 29 | 30 | public function getProxyFactoryCode(Definition $definition, string $id, string $factoryCode): string 31 | { 32 | return ''; 33 | } 34 | 35 | public function getProxyCode(Definition $definition, ?string $id = null): string 36 | { 37 | return ''; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Loader/ClosureLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader; 13 | 14 | use Symfony\Component\Config\Loader\Loader; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | 17 | /** 18 | * ClosureLoader loads service definitions from a PHP closure. 19 | * 20 | * The Closure has access to the container as its first argument. 21 | * 22 | * @author Fabien Potencier 23 | */ 24 | class ClosureLoader extends Loader 25 | { 26 | public function __construct( 27 | private ContainerBuilder $container, 28 | ?string $env = null, 29 | ) { 30 | parent::__construct($env); 31 | } 32 | 33 | public function load(mixed $resource, ?string $type = null): mixed 34 | { 35 | return $resource($this->container, $this->env); 36 | } 37 | 38 | public function supports(mixed $resource, ?string $type = null): bool 39 | { 40 | return $resource instanceof \Closure; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Loader/Configurator/AliasConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Alias; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class AliasConfigurator extends AbstractServiceConfigurator 20 | { 21 | use Traits\DeprecateTrait; 22 | use Traits\PublicTrait; 23 | 24 | public const FACTORY = 'alias'; 25 | 26 | public function __construct(ServicesConfigurator $parent, Alias $alias) 27 | { 28 | $this->parent = $parent; 29 | $this->definition = $alias; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Loader/Configurator/ClosureReferenceConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | class ClosureReferenceConfigurator extends ReferenceConfigurator 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /Loader/Configurator/DefaultsConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | 17 | /** 18 | * @author Nicolas Grekas 19 | */ 20 | class DefaultsConfigurator extends AbstractServiceConfigurator 21 | { 22 | use Traits\AutoconfigureTrait; 23 | use Traits\AutowireTrait; 24 | use Traits\BindTrait; 25 | use Traits\PublicTrait; 26 | 27 | public const FACTORY = 'defaults'; 28 | 29 | public function __construct( 30 | ServicesConfigurator $parent, 31 | Definition $definition, 32 | private ?string $path = null, 33 | ) { 34 | parent::__construct($parent, $definition, null, []); 35 | } 36 | 37 | /** 38 | * Adds a tag for this definition. 39 | * 40 | * @return $this 41 | * 42 | * @throws InvalidArgumentException when an invalid tag name or attribute is provided 43 | */ 44 | final public function tag(string $name, array $attributes = []): static 45 | { 46 | if ('' === $name) { 47 | throw new InvalidArgumentException('The tag name in "_defaults" must be a non-empty string.'); 48 | } 49 | 50 | $this->validateAttributes($name, $attributes); 51 | 52 | $this->definition->addTag($name, $attributes); 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * Defines an instanceof-conditional to be applied to following service definitions. 59 | */ 60 | final public function instanceof(string $fqcn): InstanceofConfigurator 61 | { 62 | return $this->parent->instanceof($fqcn); 63 | } 64 | 65 | private function validateAttributes(string $tag, array $attributes, array $path = []): void 66 | { 67 | foreach ($attributes as $name => $value) { 68 | if (\is_array($value)) { 69 | $this->validateAttributes($tag, $value, [...$path, $name]); 70 | } elseif (!\is_scalar($value ?? '')) { 71 | $name = implode('.', [...$path, $name]); 72 | throw new InvalidArgumentException(\sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type or an array of scalar-type.', $tag, $name)); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Loader/Configurator/FromCallableConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class FromCallableConfigurator extends AbstractServiceConfigurator 20 | { 21 | use Traits\AbstractTrait; 22 | use Traits\AutoconfigureTrait; 23 | use Traits\AutowireTrait; 24 | use Traits\BindTrait; 25 | use Traits\DecorateTrait; 26 | use Traits\DeprecateTrait; 27 | use Traits\LazyTrait; 28 | use Traits\PublicTrait; 29 | use Traits\ShareTrait; 30 | use Traits\TagTrait; 31 | 32 | public const FACTORY = 'services'; 33 | 34 | public function __construct( 35 | private ServiceConfigurator $serviceConfigurator, 36 | Definition $definition, 37 | ) { 38 | parent::__construct($serviceConfigurator->parent, $definition, $serviceConfigurator->id); 39 | } 40 | 41 | public function __destruct() 42 | { 43 | $this->serviceConfigurator->__destruct(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Loader/Configurator/InlineServiceConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class InlineServiceConfigurator extends AbstractConfigurator 20 | { 21 | use Traits\ArgumentTrait; 22 | use Traits\AutowireTrait; 23 | use Traits\BindTrait; 24 | use Traits\CallTrait; 25 | use Traits\ConfiguratorTrait; 26 | use Traits\ConstructorTrait; 27 | use Traits\FactoryTrait; 28 | use Traits\FileTrait; 29 | use Traits\LazyTrait; 30 | use Traits\ParentTrait; 31 | use Traits\PropertyTrait; 32 | use Traits\TagTrait; 33 | 34 | public const FACTORY = 'service'; 35 | 36 | private string $id = '[inline]'; 37 | private bool $allowParent = true; 38 | private ?string $path = null; 39 | 40 | public function __construct(Definition $definition) 41 | { 42 | $this->definition = $definition; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Loader/Configurator/InstanceofConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class InstanceofConfigurator extends AbstractServiceConfigurator 20 | { 21 | use Traits\AutowireTrait; 22 | use Traits\BindTrait; 23 | use Traits\CallTrait; 24 | use Traits\ConfiguratorTrait; 25 | use Traits\ConstructorTrait; 26 | use Traits\LazyTrait; 27 | use Traits\PropertyTrait; 28 | use Traits\PublicTrait; 29 | use Traits\ShareTrait; 30 | use Traits\TagTrait; 31 | 32 | public const FACTORY = 'instanceof'; 33 | 34 | public function __construct( 35 | ServicesConfigurator $parent, 36 | Definition $definition, 37 | string $id, 38 | private ?string $path = null, 39 | ) { 40 | parent::__construct($parent, $definition, $id, []); 41 | } 42 | 43 | /** 44 | * Defines an instanceof-conditional to be applied to following service definitions. 45 | */ 46 | final public function instanceof(string $fqcn): self 47 | { 48 | return $this->parent->instanceof($fqcn); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Loader/Configurator/ParametersConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | use Symfony\Component\ExpressionLanguage\Expression; 17 | 18 | /** 19 | * @author Nicolas Grekas 20 | */ 21 | class ParametersConfigurator extends AbstractConfigurator 22 | { 23 | public const FACTORY = 'parameters'; 24 | 25 | public function __construct( 26 | private ContainerBuilder $container, 27 | ) { 28 | } 29 | 30 | /** 31 | * @return $this 32 | */ 33 | final public function set(string $name, mixed $value): static 34 | { 35 | if ($value instanceof Expression) { 36 | throw new InvalidArgumentException(\sprintf('Using an expression in parameter "%s" is not allowed.', $name)); 37 | } 38 | 39 | $this->container->setParameter($name, static::processValue($value, true)); 40 | 41 | return $this; 42 | } 43 | 44 | /** 45 | * @return $this 46 | */ 47 | final public function __invoke(string $name, mixed $value): static 48 | { 49 | return $this->set($name, $value); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Loader/Configurator/PrototypeConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\Definition; 15 | use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; 16 | 17 | /** 18 | * @author Nicolas Grekas 19 | */ 20 | class PrototypeConfigurator extends AbstractServiceConfigurator 21 | { 22 | use Traits\AbstractTrait; 23 | use Traits\ArgumentTrait; 24 | use Traits\AutoconfigureTrait; 25 | use Traits\AutowireTrait; 26 | use Traits\BindTrait; 27 | use Traits\CallTrait; 28 | use Traits\ConfiguratorTrait; 29 | use Traits\ConstructorTrait; 30 | use Traits\DeprecateTrait; 31 | use Traits\FactoryTrait; 32 | use Traits\LazyTrait; 33 | use Traits\ParentTrait; 34 | use Traits\PropertyTrait; 35 | use Traits\PublicTrait; 36 | use Traits\ShareTrait; 37 | use Traits\TagTrait; 38 | 39 | public const FACTORY = 'load'; 40 | 41 | private ?array $excludes = null; 42 | 43 | public function __construct( 44 | ServicesConfigurator $parent, 45 | private PhpFileLoader $loader, 46 | Definition $defaults, 47 | string $namespace, 48 | private string $resource, 49 | private bool $allowParent, 50 | private ?string $path = null, 51 | ) { 52 | $definition = new Definition(); 53 | if (!$defaults->isPublic() || !$defaults->isPrivate()) { 54 | $definition->setPublic($defaults->isPublic()); 55 | } 56 | $definition->setAutowired($defaults->isAutowired()); 57 | $definition->setAutoconfigured($defaults->isAutoconfigured()); 58 | // deep clone, to avoid multiple process of the same instance in the passes 59 | $definition->setBindings(unserialize(serialize($defaults->getBindings()))); 60 | $definition->setChanges([]); 61 | 62 | parent::__construct($parent, $definition, $namespace, $defaults->getTags()); 63 | } 64 | 65 | public function __destruct() 66 | { 67 | parent::__destruct(); 68 | 69 | if (isset($this->loader)) { 70 | $this->loader->registerClasses($this->definition, $this->id, $this->resource, $this->excludes, $this->path); 71 | } 72 | unset($this->loader); 73 | } 74 | 75 | /** 76 | * Excludes files from registration using glob patterns. 77 | * 78 | * @param string[]|string $excludes 79 | * 80 | * @return $this 81 | */ 82 | final public function exclude(array|string $excludes): static 83 | { 84 | $this->excludes = (array) $excludes; 85 | 86 | return $this; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Loader/Configurator/ReferenceConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class ReferenceConfigurator extends AbstractConfigurator 20 | { 21 | /** @internal */ 22 | protected string $id; 23 | 24 | /** @internal */ 25 | protected int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; 26 | 27 | public function __construct(string $id) 28 | { 29 | $this->id = $id; 30 | } 31 | 32 | /** 33 | * @return $this 34 | */ 35 | final public function ignoreOnInvalid(): static 36 | { 37 | $this->invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * @return $this 44 | */ 45 | final public function nullOnInvalid(): static 46 | { 47 | $this->invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * @return $this 54 | */ 55 | final public function ignoreOnUninitialized(): static 56 | { 57 | $this->invalidBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE; 58 | 59 | return $this; 60 | } 61 | 62 | public function __toString(): string 63 | { 64 | return $this->id; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Loader/Configurator/ServiceConfigurator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Definition; 16 | 17 | /** 18 | * @author Nicolas Grekas 19 | */ 20 | class ServiceConfigurator extends AbstractServiceConfigurator 21 | { 22 | use Traits\AbstractTrait; 23 | use Traits\ArgumentTrait; 24 | use Traits\AutoconfigureTrait; 25 | use Traits\AutowireTrait; 26 | use Traits\BindTrait; 27 | use Traits\CallTrait; 28 | use Traits\ClassTrait; 29 | use Traits\ConfiguratorTrait; 30 | use Traits\ConstructorTrait; 31 | use Traits\DecorateTrait; 32 | use Traits\DeprecateTrait; 33 | use Traits\FactoryTrait; 34 | use Traits\FileTrait; 35 | use Traits\FromCallableTrait; 36 | use Traits\LazyTrait; 37 | use Traits\ParentTrait; 38 | use Traits\PropertyTrait; 39 | use Traits\PublicTrait; 40 | use Traits\ShareTrait; 41 | use Traits\SyntheticTrait; 42 | use Traits\TagTrait; 43 | 44 | public const FACTORY = 'services'; 45 | 46 | private bool $destructed = false; 47 | 48 | public function __construct( 49 | private ContainerBuilder $container, 50 | private array $instanceof, 51 | private bool $allowParent, 52 | ServicesConfigurator $parent, 53 | Definition $definition, 54 | ?string $id, 55 | array $defaultTags, 56 | private ?string $path = null, 57 | ) { 58 | parent::__construct($parent, $definition, $id, $defaultTags); 59 | } 60 | 61 | public function __destruct() 62 | { 63 | if ($this->destructed) { 64 | return; 65 | } 66 | $this->destructed = true; 67 | 68 | parent::__destruct(); 69 | 70 | $this->container->removeBindings($this->id); 71 | $this->container->setDefinition($this->id, $this->definition->setInstanceofConditionals($this->instanceof)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/AbstractTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait AbstractTrait 15 | { 16 | /** 17 | * Whether this definition is abstract, that means it merely serves as a 18 | * template for other definitions. 19 | * 20 | * @return $this 21 | */ 22 | final public function abstract(bool $abstract = true): static 23 | { 24 | $this->definition->setAbstract($abstract); 25 | 26 | return $this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ArgumentTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait ArgumentTrait 15 | { 16 | /** 17 | * Sets the arguments to pass to the service constructor/factory method. 18 | * 19 | * @return $this 20 | */ 21 | final public function args(array $arguments): static 22 | { 23 | $this->definition->setArguments(static::processValue($arguments, true)); 24 | 25 | return $this; 26 | } 27 | 28 | /** 29 | * Sets one argument to pass to the service constructor/factory method. 30 | * 31 | * @return $this 32 | */ 33 | final public function arg(string|int $key, mixed $value): static 34 | { 35 | $this->definition->setArgument($key, static::processValue($value, true)); 36 | 37 | return $this; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/AutoconfigureTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | trait AutoconfigureTrait 17 | { 18 | /** 19 | * Sets whether or not instanceof conditionals should be prepended with a global set. 20 | * 21 | * @return $this 22 | * 23 | * @throws InvalidArgumentException when a parent is already set 24 | */ 25 | final public function autoconfigure(bool $autoconfigured = true): static 26 | { 27 | $this->definition->setAutoconfigured($autoconfigured); 28 | 29 | return $this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/AutowireTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait AutowireTrait 15 | { 16 | /** 17 | * Enables/disables autowiring. 18 | * 19 | * @return $this 20 | */ 21 | final public function autowire(bool $autowired = true): static 22 | { 23 | $this->definition->setAutowired($autowired); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/BindTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Argument\BoundArgument; 15 | use Symfony\Component\DependencyInjection\Loader\Configurator\DefaultsConfigurator; 16 | use Symfony\Component\DependencyInjection\Loader\Configurator\InstanceofConfigurator; 17 | 18 | trait BindTrait 19 | { 20 | /** 21 | * Sets bindings. 22 | * 23 | * Bindings map $named or FQCN arguments to values that should be 24 | * injected in the matching parameters (of the constructor, of methods 25 | * called and of controller actions). 26 | * 27 | * @param string $nameOrFqcn A parameter name with its "$" prefix, or an FQCN 28 | * @param mixed $valueOrRef The value or reference to bind 29 | * 30 | * @return $this 31 | */ 32 | final public function bind(string $nameOrFqcn, mixed $valueOrRef): static 33 | { 34 | $valueOrRef = static::processValue($valueOrRef, true); 35 | $bindings = $this->definition->getBindings(); 36 | $type = $this instanceof DefaultsConfigurator ? BoundArgument::DEFAULTS_BINDING : ($this instanceof InstanceofConfigurator ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING); 37 | $bindings[$nameOrFqcn] = new BoundArgument($valueOrRef, true, $type, $this->path ?? null); 38 | $this->definition->setBindings($bindings); 39 | 40 | return $this; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/CallTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | trait CallTrait 17 | { 18 | /** 19 | * Adds a method to call after service initialization. 20 | * 21 | * @param string $method The method name to call 22 | * @param array $arguments An array of arguments to pass to the method call 23 | * @param bool $returnsClone Whether the call returns the service instance or not 24 | * 25 | * @return $this 26 | * 27 | * @throws InvalidArgumentException on empty $method param 28 | */ 29 | final public function call(string $method, array $arguments = [], bool $returnsClone = false): static 30 | { 31 | $this->definition->addMethodCall($method, static::processValue($arguments, true), $returnsClone); 32 | 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ClassTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait ClassTrait 15 | { 16 | /** 17 | * Sets the service class. 18 | * 19 | * @return $this 20 | */ 21 | final public function class(?string $class): static 22 | { 23 | $this->definition->setClass($class); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ConfiguratorTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator; 15 | 16 | trait ConfiguratorTrait 17 | { 18 | /** 19 | * Sets a configurator to call after the service is fully initialized. 20 | * 21 | * @return $this 22 | */ 23 | final public function configurator(string|array|ReferenceConfigurator $configurator): static 24 | { 25 | $this->definition->setConfigurator(static::processValue($configurator, true)); 26 | 27 | return $this; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ConstructorTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait ConstructorTrait 15 | { 16 | /** 17 | * Sets a static constructor. 18 | * 19 | * @return $this 20 | */ 21 | final public function constructor(string $constructor): static 22 | { 23 | $this->definition->setFactory([null, $constructor]); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/DecorateTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | 17 | trait DecorateTrait 18 | { 19 | /** 20 | * Sets the service that this service is decorating. 21 | * 22 | * @param string|null $id The decorated service id, use null to remove decoration 23 | * 24 | * @return $this 25 | * 26 | * @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals 27 | */ 28 | final public function decorate(?string $id, ?string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static 29 | { 30 | $this->definition->setDecoratedService($id, $renamedId, $priority, $invalidBehavior); 31 | 32 | return $this; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/DeprecateTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | trait DeprecateTrait 17 | { 18 | /** 19 | * Whether this definition is deprecated, that means it should not be called anymore. 20 | * 21 | * @param string $package The name of the composer package that is triggering the deprecation 22 | * @param string $version The version of the package that introduced the deprecation 23 | * @param string $message The deprecation message to use 24 | * 25 | * @return $this 26 | * 27 | * @throws InvalidArgumentException when the message template is invalid 28 | */ 29 | final public function deprecate(string $package, string $version, string $message): static 30 | { 31 | $this->definition->setDeprecated($package, $version, $message); 32 | 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/FactoryTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator; 16 | use Symfony\Component\ExpressionLanguage\Expression; 17 | 18 | trait FactoryTrait 19 | { 20 | /** 21 | * Sets a factory. 22 | * 23 | * @return $this 24 | */ 25 | final public function factory(string|array|ReferenceConfigurator|Expression $factory): static 26 | { 27 | if (\is_string($factory) && 1 === substr_count($factory, ':')) { 28 | $factoryParts = explode(':', $factory); 29 | 30 | throw new InvalidArgumentException(\sprintf('Invalid factory "%s": the "service:method" notation is not available when using PHP-based DI configuration. Use "[service(\'%s\'), \'%s\']" instead.', $factory, $factoryParts[0], $factoryParts[1])); 31 | } 32 | 33 | if ($factory instanceof Expression) { 34 | $factory = '@='.$factory; 35 | } 36 | 37 | $this->definition->setFactory(static::processValue($factory, true)); 38 | 39 | return $this; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/FileTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait FileTrait 15 | { 16 | /** 17 | * Sets a file to require before creating the service. 18 | * 19 | * @return $this 20 | */ 21 | final public function file(string $file): static 22 | { 23 | $this->definition->setFile($file); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/FromCallableTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\ChildDefinition; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | use Symfony\Component\DependencyInjection\Loader\Configurator\FromCallableConfigurator; 17 | use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator; 18 | use Symfony\Component\ExpressionLanguage\Expression; 19 | 20 | trait FromCallableTrait 21 | { 22 | final public function fromCallable(string|array|ReferenceConfigurator|Expression $callable): FromCallableConfigurator 23 | { 24 | if ($this->definition instanceof ChildDefinition) { 25 | throw new InvalidArgumentException('The configuration key "parent" is unsupported when using "fromCallable()".'); 26 | } 27 | 28 | foreach ([ 29 | 'synthetic' => 'isSynthetic', 30 | 'factory' => 'getFactory', 31 | 'file' => 'getFile', 32 | 'arguments' => 'getArguments', 33 | 'properties' => 'getProperties', 34 | 'configurator' => 'getConfigurator', 35 | 'calls' => 'getMethodCalls', 36 | ] as $key => $method) { 37 | if ($this->definition->$method()) { 38 | throw new InvalidArgumentException(\sprintf('The configuration key "%s" is unsupported when using "fromCallable()".', $key)); 39 | } 40 | } 41 | 42 | $this->definition->setFactory(['Closure', 'fromCallable']); 43 | 44 | if (\is_string($callable) && 1 === substr_count($callable, ':')) { 45 | $parts = explode(':', $callable); 46 | 47 | throw new InvalidArgumentException(\sprintf('Invalid callable "%s": the "service:method" notation is not available when using PHP-based DI configuration. Use "[service(\'%s\'), \'%s\']" instead.', $callable, $parts[0], $parts[1])); 48 | } 49 | 50 | if ($callable instanceof Expression) { 51 | $callable = '@='.$callable; 52 | } 53 | 54 | $this->definition->setArguments([static::processValue($callable, true)]); 55 | 56 | if ('Closure' !== ($this->definition->getClass() ?? 'Closure')) { 57 | $this->definition->setLazy(true); 58 | } else { 59 | $this->definition->setClass('Closure'); 60 | } 61 | 62 | return new FromCallableConfigurator($this, $this->definition); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/LazyTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait LazyTrait 15 | { 16 | /** 17 | * Sets the lazy flag of this service. 18 | * 19 | * @param bool|string $lazy A FQCN to derivate the lazy proxy from or `true` to make it extend from the definition's class 20 | * 21 | * @return $this 22 | */ 23 | final public function lazy(bool|string $lazy = true): static 24 | { 25 | $this->definition->setLazy((bool) $lazy); 26 | if (\is_string($lazy)) { 27 | $this->definition->addTag('proxy', ['interface' => $lazy]); 28 | } 29 | 30 | return $this; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ParentTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\ChildDefinition; 15 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 16 | 17 | trait ParentTrait 18 | { 19 | /** 20 | * Sets the Definition to inherit from. 21 | * 22 | * @return $this 23 | * 24 | * @throws InvalidArgumentException when parent cannot be set 25 | */ 26 | final public function parent(string $parent): static 27 | { 28 | if (!$this->allowParent) { 29 | throw new InvalidArgumentException(\sprintf('A parent cannot be defined when either "_instanceof" or "_defaults" are also defined for service prototype "%s".', $this->id)); 30 | } 31 | 32 | if ($this->definition instanceof ChildDefinition) { 33 | $this->definition->setParent($parent); 34 | } else { 35 | // cast Definition to ChildDefinition 36 | $definition = serialize($this->definition); 37 | $definition = substr_replace($definition, '53', 2, 2); 38 | $definition = substr_replace($definition, 'Child', 44, 0); 39 | $definition = unserialize($definition); 40 | 41 | $this->definition = $definition->setParent($parent); 42 | } 43 | 44 | return $this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/PropertyTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait PropertyTrait 15 | { 16 | /** 17 | * Sets a specific property. 18 | * 19 | * @return $this 20 | */ 21 | final public function property(string $name, mixed $value): static 22 | { 23 | $this->definition->setProperty($name, static::processValue($value, true)); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/PublicTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait PublicTrait 15 | { 16 | /** 17 | * @return $this 18 | */ 19 | final public function public(): static 20 | { 21 | $this->definition->setPublic(true); 22 | 23 | return $this; 24 | } 25 | 26 | /** 27 | * @return $this 28 | */ 29 | final public function private(): static 30 | { 31 | $this->definition->setPublic(false); 32 | 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/ShareTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait ShareTrait 15 | { 16 | /** 17 | * Sets if the service must be shared or not. 18 | * 19 | * @return $this 20 | */ 21 | final public function share(bool $shared = true): static 22 | { 23 | $this->definition->setShared($shared); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/SyntheticTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | trait SyntheticTrait 15 | { 16 | /** 17 | * Sets whether this definition is synthetic, that is not constructed by the 18 | * container, but dynamically injected. 19 | * 20 | * @return $this 21 | */ 22 | final public function synthetic(bool $synthetic = true): static 23 | { 24 | $this->definition->setSynthetic($synthetic); 25 | 26 | return $this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Loader/Configurator/Traits/TagTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | 16 | trait TagTrait 17 | { 18 | /** 19 | * Adds a tag for this definition. 20 | * 21 | * @return $this 22 | */ 23 | final public function tag(string $name, array $attributes = []): static 24 | { 25 | if ('' === $name) { 26 | throw new InvalidArgumentException(\sprintf('The tag name for service "%s" must be a non-empty string.', $this->id)); 27 | } 28 | 29 | $this->validateAttributes($name, $attributes); 30 | 31 | $this->definition->addTag($name, $attributes); 32 | 33 | return $this; 34 | } 35 | 36 | private function validateAttributes(string $tag, array $attributes, array $path = []): void 37 | { 38 | foreach ($attributes as $name => $value) { 39 | if (\is_array($value)) { 40 | $this->validateAttributes($tag, $value, [...$path, $name]); 41 | } elseif (!\is_scalar($value ?? '')) { 42 | $name = implode('.', [...$path, $name]); 43 | throw new InvalidArgumentException(\sprintf('A tag attribute must be of a scalar-type or an array of scalar-types for service "%s", tag "%s", attribute "%s".', $this->id, $tag, $name)); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Loader/DirectoryLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader; 13 | 14 | /** 15 | * DirectoryLoader is a recursive loader to go through directories. 16 | * 17 | * @author Sebastien Lavoie 18 | */ 19 | class DirectoryLoader extends FileLoader 20 | { 21 | public function load(mixed $file, ?string $type = null): mixed 22 | { 23 | $file = rtrim($file, '/'); 24 | $path = $this->locator->locate($file); 25 | $this->container->fileExists($path, false); 26 | 27 | foreach (scandir($path) as $dir) { 28 | if ('.' !== $dir[0]) { 29 | if (is_dir($path.'/'.$dir)) { 30 | $dir .= '/'; // append / to allow recursion 31 | } 32 | 33 | $this->setCurrentDir($path); 34 | 35 | $this->import($dir, null, false, $path); 36 | } 37 | } 38 | 39 | return null; 40 | } 41 | 42 | public function supports(mixed $resource, ?string $type = null): bool 43 | { 44 | if ('directory' === $type) { 45 | return true; 46 | } 47 | 48 | return null === $type && \is_string($resource) && str_ends_with($resource, '/'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Loader/GlobFileLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader; 13 | 14 | /** 15 | * GlobFileLoader loads files from a glob pattern. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | class GlobFileLoader extends FileLoader 20 | { 21 | public function load(mixed $resource, ?string $type = null): mixed 22 | { 23 | foreach ($this->glob($resource, false, $globResource) as $path => $info) { 24 | $this->import($path); 25 | } 26 | 27 | $this->container->addResource($globResource); 28 | 29 | return null; 30 | } 31 | 32 | public function supports(mixed $resource, ?string $type = null): bool 33 | { 34 | return 'glob' === $type; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Loader/UndefinedExtensionHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\Loader; 13 | 14 | class UndefinedExtensionHandler 15 | { 16 | private const BUNDLE_EXTENSIONS = [ 17 | 'debug' => 'DebugBundle', 18 | 'doctrine' => 'DoctrineBundle', 19 | 'doctrine_migrations' => 'DoctrineMigrationsBundle', 20 | 'framework' => 'FrameworkBundle', 21 | 'maker' => 'MakerBundle', 22 | 'monolog' => 'MonologBundle', 23 | 'security' => 'SecurityBundle', 24 | 'twig' => 'TwigBundle', 25 | 'twig_component' => 'TwigComponentBundle', 26 | 'ux_icons' => 'UXIconsBundle', 27 | 'web_profiler' => 'WebProfilerBundle', 28 | ]; 29 | 30 | public static function getErrorMessage(string $extensionName, ?string $loadingFilePath, string $namespaceOrAlias, array $foundExtensionNamespaces): string 31 | { 32 | $message = ''; 33 | if (isset(self::BUNDLE_EXTENSIONS[$extensionName])) { 34 | $message .= \sprintf('Did you forget to install or enable the %s? ', self::BUNDLE_EXTENSIONS[$extensionName]); 35 | } 36 | 37 | $message .= match (true) { 38 | \is_string($loadingFilePath) => \sprintf('There is no extension able to load the configuration for "%s" (in "%s"). ', $extensionName, $loadingFilePath), 39 | default => \sprintf('There is no extension able to load the configuration for "%s". ', $extensionName), 40 | }; 41 | 42 | return $message.\sprintf('Looked for namespace "%s", found "%s".', $namespaceOrAlias, $foundExtensionNamespaces ? implode('", "', $foundExtensionNamespaces) : 'none'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Parameter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * Parameter represents a parameter reference. 16 | * 17 | * @author Fabien Potencier 18 | */ 19 | class Parameter 20 | { 21 | public function __construct( 22 | private string $id, 23 | ) { 24 | } 25 | 26 | public function __toString(): string 27 | { 28 | return $this->id; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ParameterBag/ContainerBag.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\ParameterBag; 13 | 14 | use Symfony\Component\DependencyInjection\Container; 15 | 16 | /** 17 | * @author Nicolas Grekas 18 | */ 19 | class ContainerBag extends FrozenParameterBag implements ContainerBagInterface 20 | { 21 | public function __construct( 22 | private Container $container, 23 | ) { 24 | } 25 | 26 | public function all(): array 27 | { 28 | return $this->container->getParameterBag()->all(); 29 | } 30 | 31 | public function get(string $name): array|bool|string|int|float|\UnitEnum|null 32 | { 33 | return $this->container->getParameter($name); 34 | } 35 | 36 | public function has(string $name): bool 37 | { 38 | return $this->container->hasParameter($name); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ParameterBag/ContainerBagInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\ParameterBag; 13 | 14 | use Psr\Container\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; 16 | 17 | /** 18 | * ContainerBagInterface is the interface implemented by objects that manage service container parameters. 19 | * 20 | * @author Nicolas Grekas 21 | */ 22 | interface ContainerBagInterface extends ContainerInterface 23 | { 24 | /** 25 | * Gets the service container parameters. 26 | */ 27 | public function all(): array; 28 | 29 | /** 30 | * Replaces parameter placeholders (%name%) by their values. 31 | * 32 | * @template TValue of array|scalar 33 | * 34 | * @param TValue $value 35 | * 36 | * @psalm-return (TValue is scalar ? array|scalar : array) 37 | * 38 | * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist 39 | */ 40 | public function resolveValue(mixed $value): mixed; 41 | 42 | /** 43 | * Escape parameter placeholders %. 44 | */ 45 | public function escapeValue(mixed $value): mixed; 46 | 47 | /** 48 | * Unescape parameter placeholders %. 49 | */ 50 | public function unescapeValue(mixed $value): mixed; 51 | } 52 | -------------------------------------------------------------------------------- /ParameterBag/FrozenParameterBag.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\ParameterBag; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\LogicException; 15 | 16 | /** 17 | * Holds read-only parameters. 18 | * 19 | * @author Fabien Potencier 20 | */ 21 | class FrozenParameterBag extends ParameterBag 22 | { 23 | /** 24 | * For performance reasons, the constructor assumes that 25 | * all keys are already lowercased. 26 | * 27 | * This is always the case when used internally. 28 | */ 29 | public function __construct( 30 | array $parameters = [], 31 | protected array $deprecatedParameters = [], 32 | protected array $nonEmptyParameters = [], 33 | ) { 34 | $this->parameters = $parameters; 35 | $this->resolved = true; 36 | } 37 | 38 | public function clear(): never 39 | { 40 | throw new LogicException('Impossible to call clear() on a frozen ParameterBag.'); 41 | } 42 | 43 | public function add(array $parameters): never 44 | { 45 | throw new LogicException('Impossible to call add() on a frozen ParameterBag.'); 46 | } 47 | 48 | public function set(string $name, array|bool|string|int|float|\UnitEnum|null $value): never 49 | { 50 | throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); 51 | } 52 | 53 | public function deprecate(string $name, string $package, string $version, string $message = 'The parameter "%s" is deprecated.'): never 54 | { 55 | throw new LogicException('Impossible to call deprecate() on a frozen ParameterBag.'); 56 | } 57 | 58 | public function cannotBeEmpty(string $name, string $message = 'A non-empty parameter "%s" is required.'): never 59 | { 60 | throw new LogicException('Impossible to call cannotBeEmpty() on a frozen ParameterBag.'); 61 | } 62 | 63 | public function remove(string $name): never 64 | { 65 | throw new LogicException('Impossible to call remove() on a frozen ParameterBag.'); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ParameterBag/ParameterBagInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection\ParameterBag; 13 | 14 | use Symfony\Component\DependencyInjection\Exception\LogicException; 15 | use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; 16 | 17 | /** 18 | * ParameterBagInterface is the interface implemented by objects that manage service container parameters. 19 | * 20 | * @author Fabien Potencier 21 | */ 22 | interface ParameterBagInterface 23 | { 24 | /** 25 | * Clears all parameters. 26 | * 27 | * @throws LogicException if the ParameterBagInterface cannot be cleared 28 | */ 29 | public function clear(): void; 30 | 31 | /** 32 | * Adds parameters to the service container parameters. 33 | * 34 | * @throws LogicException if the parameter cannot be added 35 | */ 36 | public function add(array $parameters): void; 37 | 38 | /** 39 | * Gets the service container parameters. 40 | */ 41 | public function all(): array; 42 | 43 | /** 44 | * Gets a service container parameter. 45 | * 46 | * @throws ParameterNotFoundException if the parameter is not defined 47 | */ 48 | public function get(string $name): array|bool|string|int|float|\UnitEnum|null; 49 | 50 | /** 51 | * Removes a parameter. 52 | */ 53 | public function remove(string $name): void; 54 | 55 | /** 56 | * Sets a service container parameter. 57 | * 58 | * @throws LogicException if the parameter cannot be set 59 | */ 60 | public function set(string $name, array|bool|string|int|float|\UnitEnum|null $value): void; 61 | 62 | /** 63 | * Returns true if a parameter name is defined. 64 | */ 65 | public function has(string $name): bool; 66 | 67 | /** 68 | * Replaces parameter placeholders (%name%) by their values for all parameters. 69 | */ 70 | public function resolve(): void; 71 | 72 | /** 73 | * Replaces parameter placeholders (%name%) by their values. 74 | * 75 | * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist 76 | */ 77 | public function resolveValue(mixed $value): mixed; 78 | 79 | /** 80 | * Escape parameter placeholders %. 81 | */ 82 | public function escapeValue(mixed $value): mixed; 83 | 84 | /** 85 | * Unescape parameter placeholders %. 86 | */ 87 | public function unescapeValue(mixed $value): mixed; 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DependencyInjection Component 2 | ============================= 3 | 4 | The DependencyInjection component allows you to standardize and centralize the 5 | way objects are constructed in your application. 6 | 7 | Resources 8 | --------- 9 | 10 | * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) 11 | * [Contributing](https://symfony.com/doc/current/contributing/index.html) 12 | * [Report issues](https://github.com/symfony/symfony/issues) and 13 | [send Pull Requests](https://github.com/symfony/symfony/pulls) 14 | in the [main Symfony repository](https://github.com/symfony/symfony) 15 | -------------------------------------------------------------------------------- /Reference.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * Reference represents a service reference. 16 | * 17 | * @author Fabien Potencier 18 | */ 19 | class Reference 20 | { 21 | public function __construct( 22 | private string $id, 23 | private int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 24 | ) { 25 | } 26 | 27 | public function __toString(): string 28 | { 29 | return $this->id; 30 | } 31 | 32 | /** 33 | * Returns the behavior to be used when the service does not exist. 34 | */ 35 | public function getInvalidBehavior(): int 36 | { 37 | return $this->invalidBehavior; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ReverseContainer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | use Psr\Container\ContainerInterface; 15 | use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 16 | 17 | /** 18 | * Turns public and "container.reversible" services back to their ids. 19 | * 20 | * @author Nicolas Grekas 21 | */ 22 | final class ReverseContainer 23 | { 24 | private \Closure $getServiceId; 25 | 26 | public function __construct( 27 | private Container $serviceContainer, 28 | private ContainerInterface $reversibleLocator, 29 | private string $tagName = 'container.reversible', 30 | ) { 31 | $this->getServiceId = \Closure::bind(fn (object $service): ?string => array_search($service, $this->services, true) ?: array_search($service, $this->privates, true) ?: null, $serviceContainer, Container::class); 32 | } 33 | 34 | /** 35 | * Returns the id of the passed object when it exists as a service. 36 | * 37 | * To be reversible, services need to be either public or be tagged with "container.reversible". 38 | */ 39 | public function getId(object $service): ?string 40 | { 41 | if ($this->serviceContainer === $service) { 42 | return 'service_container'; 43 | } 44 | 45 | if (null === $id = ($this->getServiceId)($service)) { 46 | return null; 47 | } 48 | 49 | if ($this->serviceContainer->has($id) || $this->reversibleLocator->has($id)) { 50 | return $id; 51 | } 52 | 53 | return null; 54 | } 55 | 56 | /** 57 | * @throws ServiceNotFoundException When the service is not reversible 58 | */ 59 | public function getService(string $id): object 60 | { 61 | if ($this->reversibleLocator->has($id)) { 62 | return $this->reversibleLocator->get($id); 63 | } 64 | 65 | if (isset($this->serviceContainer->getRemovedIds()[$id])) { 66 | throw new ServiceNotFoundException($id, null, null, [], \sprintf('The "%s" service is private and cannot be accessed by reference. You should either make it public, or tag it as "%s".', $id, $this->tagName)); 67 | } 68 | 69 | return $this->serviceContainer->get($id); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /StaticEnvVarLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | class StaticEnvVarLoader implements EnvVarLoaderInterface 15 | { 16 | private array $envVars; 17 | 18 | public function __construct(private EnvVarLoaderInterface $envVarLoader) 19 | { 20 | } 21 | 22 | public function loadEnvVars(): array 23 | { 24 | return $this->envVars ??= $this->envVarLoader->loadEnvVars(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TaggedContainerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * TaggedContainerInterface is the interface implemented when a container knows how to deals with tags. 16 | * 17 | * @author Fabien Potencier 18 | */ 19 | interface TaggedContainerInterface extends ContainerInterface 20 | { 21 | /** 22 | * Returns service ids for a given tag. 23 | * 24 | * @param string $name The tag name 25 | */ 26 | public function findTaggedServiceIds(string $name): array; 27 | } 28 | -------------------------------------------------------------------------------- /TypedReference.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * Represents a PHP type-hinted service reference. 16 | * 17 | * @author Nicolas Grekas 18 | */ 19 | class TypedReference extends Reference 20 | { 21 | private ?string $name; 22 | 23 | /** 24 | * @param string $id The service identifier 25 | * @param string $type The PHP type of the identified service 26 | * @param int $invalidBehavior The behavior when the service does not exist 27 | * @param string|null $name The name of the argument targeting the service 28 | * @param array $attributes The attributes to be used 29 | */ 30 | public function __construct( 31 | string $id, 32 | private string $type, 33 | int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 34 | ?string $name = null, 35 | private array $attributes = [], 36 | ) { 37 | $this->name = $type === $id ? $name : null; 38 | parent::__construct($id, $invalidBehavior); 39 | } 40 | 41 | public function getType(): string 42 | { 43 | return $this->type; 44 | } 45 | 46 | public function getName(): ?string 47 | { 48 | return $this->name; 49 | } 50 | 51 | public function getAttributes(): array 52 | { 53 | return $this->attributes; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Variable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\DependencyInjection; 13 | 14 | /** 15 | * Represents a variable. 16 | * 17 | * $var = new Variable('a'); 18 | * 19 | * will be dumped as 20 | * 21 | * $a 22 | * 23 | * by the PHP dumper. 24 | * 25 | * @author Johannes M. Schmitt 26 | */ 27 | class Variable 28 | { 29 | public function __construct( 30 | private string $name, 31 | ) { 32 | } 33 | 34 | public function __toString(): string 35 | { 36 | return $this->name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/dependency-injection", 3 | "type": "library", 4 | "description": "Allows you to standardize and centralize the way objects are constructed in your application", 5 | "keywords": [], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Fabien Potencier", 11 | "email": "fabien@symfony.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=8.2", 20 | "psr/container": "^1.1|^2.0", 21 | "symfony/deprecation-contracts": "^2.5|^3", 22 | "symfony/service-contracts": "^3.5", 23 | "symfony/var-exporter": "^6.4.20|^7.2.5" 24 | }, 25 | "require-dev": { 26 | "symfony/yaml": "^6.4|^7.0", 27 | "symfony/config": "^6.4|^7.0", 28 | "symfony/expression-language": "^6.4|^7.0" 29 | }, 30 | "conflict": { 31 | "ext-psr": "<1.1|>=2", 32 | "symfony/config": "<6.4", 33 | "symfony/finder": "<6.4", 34 | "symfony/yaml": "<6.4" 35 | }, 36 | "provide": { 37 | "psr/container-implementation": "1.1|2.0", 38 | "symfony/service-implementation": "1.1|2.0|3.0" 39 | }, 40 | "autoload": { 41 | "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" }, 42 | "exclude-from-classmap": [ 43 | "/Tests/" 44 | ] 45 | }, 46 | "minimum-stability": "dev" 47 | } 48 | --------------------------------------------------------------------------------