initial commit

This commit is contained in:
boris
2025-09-30 09:24:25 +01:00
committed by boris
parent a783a12c97
commit c7770ea03b
4695 changed files with 525784 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell under which alias a service should be registered or to use the implemented interface if no parameter is given.
*
* @author Alan Poulain <contact@alanpoulain.eu>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
final class AsAlias
{
/**
* @var list<string>
*/
public array $when = [];
/**
* @param string|null $id The id of the alias
* @param bool $public Whether to declare the alias public
* @param string|list<string> $when The environments under which the class will be registered as a service (i.e. "dev", "test", "prod")
*/
public function __construct(
public ?string $id = null,
public bool $public = false,
string|array $when = [],
) {
$this->when = (array) $when;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Declares a decorating service.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class AsDecorator
{
/**
* @param string $decorates The service id to decorate
* @param int $priority The priority of this decoration when multiple decorators are declared for the same service
* @param int $onInvalid The behavior to adopt when the decoration is invalid; must be one of the {@see ContainerInterface} constants
*/
public function __construct(
public string $decorates,
public int $priority = 0,
public int $onInvalid = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,
) {
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell under which index and priority a service class should be found in tagged iterators/locators.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
class AsTaggedItem
{
/**
* @param string|null $index The property or method to use to index the item in the iterator/locator
* @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the iterator/locator
*/
public function __construct(
public ?string $index = null,
public ?int $priority = null,
) {
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell how a base type should be autoconfigured.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
class Autoconfigure
{
/**
* @param array<array-key, array<array-key, mixed>>|string[]|null $tags The tags to add to the service
* @param array<array<mixed>>|null $calls The calls to be made when instantiating the service
* @param array<string, mixed>|null $bind The bindings to declare for the service
* @param bool|string|null $lazy Whether the service is lazy-loaded
* @param bool|null $public Whether to declare the service as public
* @param bool|null $shared Whether to declare the service as shared
* @param bool|null $autowire Whether to declare the service as autowired
* @param array<string, mixed>|null $properties The properties to define when creating the service
* @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
* @param string|null $constructor The public static method to use to instantiate the service
*/
public function __construct(
public ?array $tags = null,
public ?array $calls = null,
public ?array $bind = null,
public bool|string|null $lazy = null,
public ?bool $public = null,
public ?bool $shared = null,
public ?bool $autowire = null,
public ?array $properties = null,
public array|string|null $configurator = null,
public ?string $constructor = null,
) {
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell how a base type should be tagged.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
class AutoconfigureTag extends Autoconfigure
{
/**
* @param string|null $name The tag name to add
* @param array<array-key, mixed> $attributes The tag attributes to attach to the tag
*/
public function __construct(?string $name = null, array $attributes = [])
{
parent::__construct(
tags: [
[$name ?? 0 => $attributes],
]
);
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* Attribute to tell a parameter how to be autowired.
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class Autowire
{
public readonly string|array|Expression|Reference|ArgumentInterface|null $value;
public readonly bool|array $lazy;
/**
* Use only ONE of the following.
*
* @param string|array|ArgumentInterface|null $value Value to inject (ie "%kernel.project_dir%/some/path")
* @param string|null $service Service ID (ie "some.service")
* @param string|null $expression Expression (ie 'service("some.service").someMethod()')
* @param string|null $env Environment variable name (ie 'SOME_ENV_VARIABLE')
* @param string|null $param Parameter name (ie 'some.parameter.name')
* @param bool|class-string|class-string[] $lazy Whether to use lazy-loading for this argument
*/
public function __construct(
string|array|ArgumentInterface|null $value = null,
?string $service = null,
?string $expression = null,
?string $env = null,
?string $param = null,
bool|string|array $lazy = false,
) {
if ($this->lazy = \is_string($lazy) ? [$lazy] : $lazy) {
if (null !== ($expression ?? $env ?? $param)) {
throw new LogicException('#[Autowire] attribute cannot be $lazy and use $expression, $env, or $param.');
}
if (null !== $value && null !== $service) {
throw new LogicException('#[Autowire] attribute cannot declare $value and $service at the same time.');
}
} elseif (!(null !== $value xor null !== $service xor null !== $expression xor null !== $env xor null !== $param)) {
throw new LogicException('#[Autowire] attribute must declare exactly one of $service, $expression, $env, $param or $value.');
}
if (\is_string($value) && str_starts_with($value, '@')) {
match (true) {
str_starts_with($value, '@@') => $value = substr($value, 1),
str_starts_with($value, '@=') => $expression = substr($value, 2),
default => $service = substr($value, 1),
};
}
$this->value = match (true) {
null !== $service => new Reference($service),
null !== $expression => class_exists(Expression::class) ? new Expression($expression) : throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".'),
null !== $env => "%env($env)%",
null !== $param => "%$param%",
default => $value,
};
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Attribute to tell which callable to give to an argument of type Closure.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireCallable extends AutowireInline
{
/**
* @param string|array|null $callable The callable to autowire
* @param string|null $service The service containing the callable to autowire
* @param string|null $method The method name that will be autowired
* @param bool|class-string $lazy Whether to use lazy-loading for this argument
*/
public function __construct(
string|array|null $callable = null,
?string $service = null,
?string $method = null,
bool|string $lazy = false,
) {
if (!(null !== $callable xor null !== $service)) {
throw new LogicException('#[AutowireCallable] attribute must declare exactly one of $callable or $service.');
}
if (null === $service && null !== $method) {
throw new LogicException('#[AutowireCallable] attribute cannot have a $method without a $service.');
}
Autowire::__construct($callable ?? [new Reference($service), $method ?? '__invoke'], lazy: $lazy);
}
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
{
return (new Definition($type = \is_array($this->lazy) ? current($this->lazy) : ($type ?: 'Closure')))
->setFactory(['Closure', 'fromCallable'])
->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value])
->setLazy($this->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType());
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* Autowires the inner object of decorating services.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireDecorated
{
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
/**
* Allows inline service definition for an argument.
*
* Using this attribute on a class autowires a new instance
* which is not shared between different services.
*
* $class a FQCN, or an array to define a factory.
* Use the "@" prefix to reference a service.
*
* @author Ismail Özgün Turan <oezguen.turan@dadadev.com>
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireInline extends Autowire
{
public function __construct(string|array|null $class = null, array $arguments = [], array $calls = [], array $properties = [], ?string $parent = null, bool|string $lazy = false)
{
if (null === $class && null === $parent) {
throw new LogicException('#[AutowireInline] attribute should declare either $class or $parent.');
}
parent::__construct([
\is_array($class) ? 'factory' : 'class' => $class,
'arguments' => $arguments,
'calls' => $calls,
'properties' => $properties,
'parent' => $parent,
], lazy: $lazy);
}
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
{
static $parseDefinition;
static $yamlLoader;
$parseDefinition ??= new \ReflectionMethod(YamlFileLoader::class, 'parseDefinition');
$yamlLoader ??= $parseDefinition->getDeclaringClass()->newInstanceWithoutConstructor();
if (isset($value['factory'])) {
$value['class'] = $type;
$value['factory'][0] ??= $type;
$value['factory'][1] ??= '__invoke';
}
$class = $parameter->getDeclaringClass();
return $parseDefinition->invoke($yamlLoader, $class->name, $value, $class->getFileName(), ['autowire' => true], true);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
/**
* Autowires an iterator of services based on a tag name.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireIterator extends Autowire
{
/**
* @see ServiceSubscriberInterface::getSubscribedServices()
*
* @param string $tag A tag name to search for to populate the iterator
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
* @param string|array<string> $exclude A service id or a list of service ids to exclude
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
*/
public function __construct(
string $tag,
?string $indexAttribute = null,
?string $defaultIndexMethod = null,
?string $defaultPriorityMethod = null,
string|array $exclude = [],
bool $excludeSelf = true,
) {
parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
}
}

View File

@@ -0,0 +1,86 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Contracts\Service\Attribute\SubscribedService;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
/**
* Autowires a service locator based on a tag name or an explicit list of key => service-type pairs.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireLocator extends Autowire
{
/**
* @see ServiceSubscriberInterface::getSubscribedServices()
*
* @param string|array<string|Autowire|SubscribedService> $services A tag name or an explicit list of service ids
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the locator
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
* @param string|array $exclude A service id or a list of service ids to exclude
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the locator
*/
public function __construct(
string|array $services,
?string $indexAttribute = null,
?string $defaultIndexMethod = null,
?string $defaultPriorityMethod = null,
string|array $exclude = [],
bool $excludeSelf = true,
) {
if (\is_string($services)) {
parent::__construct(new ServiceLocatorArgument(new TaggedIteratorArgument($services, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf)));
return;
}
$references = [];
foreach ($services as $key => $type) {
$attributes = [];
if ($type instanceof Autowire) {
$references[$key] = $type;
continue;
}
if ($type instanceof SubscribedService) {
$key = $type->key ?? $key;
$attributes = $type->attributes;
$type = ($type->nullable ? '?' : '').($type->type ?? throw new InvalidArgumentException(\sprintf('When "%s" is used, a type must be set.', SubscribedService::class)));
}
if (!\is_string($type) || !preg_match('/(?(DEFINE)(?<cn>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?(DEFINE)(?<fqcn>(?&cn)(?:\\\\(?&cn))*+))^\??(?&fqcn)(?:(?:\|(?&fqcn))*+|(?:&(?&fqcn))*+)$/', $type)) {
throw new InvalidArgumentException(\sprintf('"%s" is not a PHP type for key "%s".', \is_string($type) ? $type : get_debug_type($type), $key));
}
$optionalBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
if ('?' === $type[0]) {
$type = substr($type, 1);
$optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
}
if (\is_int($name = $key)) {
$key = $type;
$name = null;
}
$references[$key] = new TypedReference($type, $type, $optionalBehavior, $name, $attributes);
}
parent::__construct(new ServiceLocatorArgument($references));
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Tells which method should be turned into a Closure based on the name of the parameter it's attached to.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireMethodOf extends AutowireCallable
{
/**
* @param string $service The service containing the method to autowire
* @param bool|class-string $lazy Whether to use lazy-loading for this argument
*/
public function __construct(string $service, bool|string $lazy = false)
{
parent::__construct([new Reference($service)], lazy: $lazy);
}
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
{
$value[1] = $parameter->name;
return parent::buildDefinition($value, $type, $parameter);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Reference;
/**
* Attribute to wrap a service in a closure that returns it.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class AutowireServiceClosure extends Autowire
{
/**
* @param string $service The service id to wrap in the closure
*/
public function __construct(string $service)
{
parent::__construct(new ServiceClosureArgument(new Reference($service)));
}
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell the class should not be registered as service.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class Exclude
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PARAMETER)]
class Lazy
{
public function __construct(
public bool|string|null $lazy = true,
) {
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* Autowires an iterator of services based on a tag name.
*
* @deprecated since Symfony 7.1, use {@see AutowireIterator} instead.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class TaggedIterator extends AutowireIterator
{
/**
* @param string $tag The tag to look for to populate the iterator
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
* @param string|string[] $exclude A service id or a list of service ids to exclude
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
*/
public function __construct(
public string $tag,
public ?string $indexAttribute = null,
public ?string $defaultIndexMethod = null,
public ?string $defaultPriorityMethod = null,
public string|array $exclude = [],
public bool $excludeSelf = true,
) {
trigger_deprecation('symfony/dependency-injection', '7.1', 'The "%s" attribute is deprecated, use "%s" instead.', self::class, AutowireIterator::class);
parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* Autowires a locator of services based on a tag name.
*
* @deprecated since Symfony 7.1, use {@see AutowireLocator} instead.
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class TaggedLocator extends AutowireLocator
{
/**
* @param string $tag The tag to look for to populate the locator
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
* @param string|string[] $exclude A service id or a list of service ids to exclude
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the locator
*/
public function __construct(
public string $tag,
public ?string $indexAttribute = null,
public ?string $defaultIndexMethod = null,
public ?string $defaultPriorityMethod = null,
public string|array $exclude = [],
public bool $excludeSelf = true,
) {
trigger_deprecation('symfony/dependency-injection', '7.1', 'The "%s" attribute is deprecated, use "%s" instead.', self::class, AutowireLocator::class);
parent::__construct($tag, $indexAttribute, $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* An attribute to tell how a dependency is used and hint named autowiring aliases.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
final class Target
{
/**
* @param string|null $name The name of the target autowiring alias
*/
public function __construct(public ?string $name = null)
{
}
public function getParsedName(): string
{
if (null === $this->name) {
throw new LogicException(\sprintf('Cannot parse the name of a #[Target] attribute that has not been resolved. Did you forget to call "%s::parseName()"?', __CLASS__));
}
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->name))));
}
public static function parseName(\ReflectionParameter $parameter, ?self &$attribute = null, ?string &$parsedName = null): string
{
$attribute = null;
if (!$target = $parameter->getAttributes(self::class)[0] ?? null) {
$parsedName = (new self($parameter->name))->getParsedName();
return $parameter->name;
}
$attribute = $target->newInstance();
$name = $attribute->name ??= $parameter->name;
$parsedName = $attribute->getParsedName();
if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $parsedName)) {
if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) {
$function = $function->class.'::'.$function->name;
} else {
$function = $function->name;
}
throw new InvalidArgumentException(\sprintf('Invalid #[Target] name "%s" on parameter "$%s" of "%s()": the first character must be a letter.', $name, $parameter->name, $function));
}
return preg_match('/^[a-zA-Z0-9_\x7f-\xff]++$/', $name) ? $name : $parsedName;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell under which environment this class should be registered as a service.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
class When
{
/**
* @param string $env The environment under which the class will be registered as a service (i.e. "dev", "test", "prod")
*/
public function __construct(public string $env)
{
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Attribute;
/**
* An attribute to tell under which environment this class should NOT be registered as a service.
*
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
class WhenNot
{
public function __construct(
public string $env,
) {
}
}