first commit

This commit is contained in:
2025-07-18 16:20:14 +07:00
commit 98af45c018
16382 changed files with 3148096 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* Represents an abstract service argument, which have to be set by a compiler pass or a DI extension.
*/
final class AbstractArgument
{
private string $text;
private string $context = '';
public function __construct(string $text = '')
{
$this->text = trim($text, '. ');
}
public function setContext(string $context): void
{
$this->context = $context.' is abstract'.('' === $this->text ? '' : ': ');
}
public function getText(): string
{
return $this->text;
}
public function getTextWithContext(): string
{
return $this->context.$this->text.'.';
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* Represents a complex argument containing nested values.
*
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
interface ArgumentInterface
{
public function getValues(): array;
/**
* @return void
*/
public function setValues(array $values);
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* @author Guilhem Niot <guilhem.niot@gmail.com>
*/
final class BoundArgument implements ArgumentInterface
{
public const SERVICE_BINDING = 0;
public const DEFAULTS_BINDING = 1;
public const INSTANCEOF_BINDING = 2;
private static int $sequence = 0;
private mixed $value;
private ?int $identifier = null;
private ?bool $used = null;
private int $type;
private ?string $file;
public function __construct(mixed $value, bool $trackUsage = true, int $type = 0, ?string $file = null)
{
$this->value = $value;
if ($trackUsage) {
$this->identifier = ++self::$sequence;
} else {
$this->used = true;
}
$this->type = $type;
$this->file = $file;
}
public function getValues(): array
{
return [$this->value, $this->identifier, $this->used, $this->type, $this->file];
}
public function setValues(array $values): void
{
if (5 === \count($values)) {
[$this->value, $this->identifier, $this->used, $this->type, $this->file] = $values;
} else {
[$this->value, $this->identifier, $this->used] = $values;
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* Represents a collection of values to lazily iterate over.
*
* @author Titouan Galopin <galopintitouan@gmail.com>
*/
class IteratorArgument implements ArgumentInterface
{
private array $values;
public function __construct(array $values)
{
$this->setValues($values);
}
public function getValues(): array
{
return $this->values;
}
/**
* @return void
*/
public function setValues(array $values)
{
$this->values = $values;
}
}

View File

@@ -0,0 +1,96 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\VarExporter\ProxyHelper;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class LazyClosure
{
public readonly object $service;
public function __construct(
private \Closure $initializer,
) {
unset($this->service);
}
public function __get(mixed $name): mixed
{
if ('service' !== $name) {
throw new InvalidArgumentException(sprintf('Cannot read property "%s" from a lazy closure.', $name));
}
if (isset($this->initializer)) {
$this->service = ($this->initializer)();
unset($this->initializer);
}
return $this->service;
}
public static function getCode(string $initializer, array $callable, Definition $definition, ContainerBuilder $container, ?string $id): string
{
$method = $callable[1];
$asClosure = 'Closure' === ($definition->getClass() ?: 'Closure');
if ($asClosure) {
$class = ($callable[0] instanceof Reference ? $container->findDefinition($callable[0]) : $callable[0])->getClass();
} else {
$class = $definition->getClass();
}
$r = $container->getReflectionClass($class);
if (null !== $id) {
$id = sprintf(' for service "%s"', $id);
}
if (!$asClosure) {
$id = str_replace('%', '%%', (string) $id);
if (!$r || !$r->isInterface()) {
throw new RuntimeException(sprintf("Cannot create adapter{$id} because \"%s\" is not an interface.", $class));
}
if (1 !== \count($method = $r->getMethods())) {
throw new RuntimeException(sprintf("Cannot create adapter{$id} because interface \"%s\" doesn't have exactly one method.", $class));
}
$method = $method[0]->name;
} elseif (!$r || !$r->hasMethod($method)) {
throw new RuntimeException("Cannot create lazy closure{$id} because its corresponding callable is invalid.");
}
$methodReflector = $r->getMethod($method);
$code = ProxyHelper::exportSignature($methodReflector, true, $args);
if ($asClosure) {
$code = ' { '.preg_replace('/: static$/', ': \\'.$r->name, $code);
} else {
$code = ' implements \\'.$r->name.' { '.$code;
}
$code = 'new class('.$initializer.') extends \\'.self::class
.$code.' { '.($methodReflector->hasReturnType() && 'void' === (string) $methodReflector->getReturnType() ? '' : 'return ').'$this->service->'.$callable[1].'('.$args.'); } '
.'}';
return $asClosure ? '('.$code.')->'.$method.'(...)' : $code;
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
trigger_deprecation('symfony/dependency-injection', '6.1', '"%s" is deprecated.', ReferenceSetArgumentTrait::class);
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Titouan Galopin <galopintitouan@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @deprecated since Symfony 6.1
*/
trait ReferenceSetArgumentTrait
{
private array $values;
/**
* @param Reference[] $values
*/
public function __construct(array $values)
{
$this->setValues($values);
}
/**
* @return Reference[]
*/
public function getValues(): array
{
return $this->values;
}
/**
* @param Reference[] $values The service references to put in the set
*
* @return void
*/
public function setValues(array $values)
{
foreach ($values as $k => $v) {
if (null !== $v && !$v instanceof Reference) {
throw new InvalidArgumentException(sprintf('A "%s" must hold only Reference instances, "%s" given.', __CLASS__, get_debug_type($v)));
}
}
$this->values = $values;
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* @internal
*/
class RewindableGenerator implements \IteratorAggregate, \Countable
{
private \Closure $generator;
private \Closure|int $count;
public function __construct(callable $generator, int|callable $count)
{
$this->generator = $generator(...);
$this->count = \is_int($count) ? $count : $count(...);
}
public function getIterator(): \Traversable
{
$g = $this->generator;
return $g();
}
public function count(): int
{
if (!\is_int($count = $this->count)) {
$this->count = $count();
}
return $this->count;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Represents a service wrapped in a memoizing closure.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ServiceClosureArgument implements ArgumentInterface
{
private array $values;
public function __construct(mixed $value)
{
$this->values = [$value];
}
public function getValues(): array
{
return $this->values;
}
/**
* @return void
*/
public function setValues(array $values)
{
if ([0] !== array_keys($values)) {
throw new InvalidArgumentException('A ServiceClosureArgument must hold one and only one value.');
}
$this->values = $values;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class ServiceLocator extends BaseServiceLocator
{
private \Closure $factory;
private array $serviceMap;
private ?array $serviceTypes;
public function __construct(\Closure $factory, array $serviceMap, ?array $serviceTypes = null)
{
$this->factory = $factory;
$this->serviceMap = $serviceMap;
$this->serviceTypes = $serviceTypes;
parent::__construct($serviceMap);
}
public function get(string $id): mixed
{
return match (\count($this->serviceMap[$id] ?? [])) {
0 => parent::get($id),
1 => $this->serviceMap[$id][0],
default => ($this->factory)(...$this->serviceMap[$id]),
};
}
public function getProvidedServices(): array
{
return $this->serviceTypes ??= array_map(fn () => '?', $this->serviceMap);
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* Represents a closure acting as a service locator.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ServiceLocatorArgument implements ArgumentInterface
{
private array $values;
private ?TaggedIteratorArgument $taggedIteratorArgument = null;
public function __construct(array|TaggedIteratorArgument $values = [])
{
if ($values instanceof TaggedIteratorArgument) {
$this->taggedIteratorArgument = $values;
$values = [];
}
$this->setValues($values);
}
public function getTaggedIteratorArgument(): ?TaggedIteratorArgument
{
return $this->taggedIteratorArgument;
}
public function getValues(): array
{
return $this->values;
}
/**
* @return void
*/
public function setValues(array $values)
{
$this->values = $values;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
/**
* Represents a collection of services found by tag name to lazily iterate over.
*
* @author Roland Franssen <franssen.roland@gmail.com>
*/
class TaggedIteratorArgument extends IteratorArgument
{
private string $tag;
private mixed $indexAttribute;
private ?string $defaultIndexMethod;
private ?string $defaultPriorityMethod;
private bool $needsIndexes;
private array $exclude;
private bool $excludeSelf = true;
/**
* @param string $tag The name of the tag identifying the target services
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
* @param array $exclude Services to exclude from the iterator
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
*/
public function __construct(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, bool $needsIndexes = false, ?string $defaultPriorityMethod = null, array $exclude = [], bool $excludeSelf = true)
{
parent::__construct([]);
if (null === $indexAttribute && $needsIndexes) {
$indexAttribute = preg_match('/[^.]++$/', $tag, $m) ? $m[0] : $tag;
}
$this->tag = $tag;
$this->indexAttribute = $indexAttribute;
$this->defaultIndexMethod = $defaultIndexMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name' : null);
$this->needsIndexes = $needsIndexes;
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Priority' : null);
$this->exclude = $exclude;
$this->excludeSelf = $excludeSelf;
}
/**
* @return string
*/
public function getTag()
{
return $this->tag;
}
public function getIndexAttribute(): ?string
{
return $this->indexAttribute;
}
public function getDefaultIndexMethod(): ?string
{
return $this->defaultIndexMethod;
}
public function needsIndexes(): bool
{
return $this->needsIndexes;
}
public function getDefaultPriorityMethod(): ?string
{
return $this->defaultPriorityMethod;
}
public function getExclude(): array
{
return $this->exclude;
}
public function excludeSelf(): bool
{
return $this->excludeSelf;
}
}