Initial Drupal 11 with DDEV setup

This commit is contained in:
gluebox
2025-10-08 11:39:17 -04:00
commit 89ef74b305
25344 changed files with 2599172 additions and 0 deletions

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
interface ArgumentInterface
{
/**
* @return mixed
*/
public function getValue();
}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
use League\Container\ContainerAwareInterface;
use ReflectionFunctionAbstract;
interface ArgumentResolverInterface extends ContainerAwareInterface
{
public function resolveArguments(array $arguments): array;
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []): array;
}

View File

@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
use League\Container\DefinitionContainerInterface;
use League\Container\Exception\{ContainerException, NotFoundException};
use League\Container\ReflectionContainer;
use Psr\Container\ContainerInterface;
use ReflectionFunctionAbstract;
use ReflectionNamedType;
trait ArgumentResolverTrait
{
public function resolveArguments(array $arguments): array
{
try {
$container = $this->getContainer();
} catch (ContainerException $e) {
$container = ($this instanceof ReflectionContainer) ? $this : null;
}
foreach ($arguments as &$arg) {
// if we have a literal, we don't want to do anything more with it
if ($arg instanceof LiteralArgumentInterface) {
$arg = $arg->getValue();
continue;
}
if ($arg instanceof ArgumentInterface) {
$argValue = $arg->getValue();
} else {
$argValue = $arg;
}
if (!is_string($argValue)) {
continue;
}
// resolve the argument from the container, if it happens to be another
// argument wrapper, use that value
if ($container instanceof ContainerInterface && $container->has($argValue)) {
try {
$arg = $container->get($argValue);
if ($arg instanceof ArgumentInterface) {
$arg = $arg->getValue();
}
continue;
} catch (NotFoundException $e) {
}
}
// if we have a default value, we use that, no more resolution as
// we expect a default/optional argument value to be literal
if ($arg instanceof DefaultValueInterface) {
$arg = $arg->getDefaultValue();
}
}
return $arguments;
}
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []): array
{
$params = $method->getParameters();
$arguments = [];
foreach ($params as $param) {
$name = $param->getName();
// if we've been given a value for the argument, treat as literal
if (array_key_exists($name, $args)) {
$arguments[] = new LiteralArgument($args[$name]);
continue;
}
$type = $param->getType();
if ($type instanceof ReflectionNamedType) {
// in PHP 8, nullable arguments have "?" prefix
$typeHint = ltrim($type->getName(), '?');
if ($param->isDefaultValueAvailable()) {
$arguments[] = new DefaultValueArgument($typeHint, $param->getDefaultValue());
continue;
}
$arguments[] = new ResolvableArgument($typeHint);
continue;
}
if ($param->isDefaultValueAvailable()) {
$arguments[] = new LiteralArgument($param->getDefaultValue());
continue;
}
throw new NotFoundException(sprintf(
'Unable to resolve a value for parameter (%s) in the function/method (%s)',
$name,
$method->getName()
));
}
return $this->resolveArguments($arguments);
}
abstract public function getContainer(): DefinitionContainerInterface;
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
class DefaultValueArgument extends ResolvableArgument implements DefaultValueInterface
{
protected $defaultValue;
public function __construct(string $value, $defaultValue = null)
{
$this->defaultValue = $defaultValue;
parent::__construct($value);
}
/**
* @return mixed|null
*/
public function getDefaultValue()
{
return $this->defaultValue;
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
interface DefaultValueInterface extends ArgumentInterface
{
/**
* @return mixed
*/
public function getDefaultValue();
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class ArrayArgument extends LiteralArgument
{
public function __construct(array $value)
{
parent::__construct($value, LiteralArgument::TYPE_ARRAY);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class BooleanArgument extends LiteralArgument
{
public function __construct(bool $value)
{
parent::__construct($value, LiteralArgument::TYPE_BOOL);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class CallableArgument extends LiteralArgument
{
public function __construct(callable $value)
{
parent::__construct($value, LiteralArgument::TYPE_CALLABLE);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class FloatArgument extends LiteralArgument
{
public function __construct(float $value)
{
parent::__construct($value, LiteralArgument::TYPE_FLOAT);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class IntegerArgument extends LiteralArgument
{
public function __construct(int $value)
{
parent::__construct($value, LiteralArgument::TYPE_INT);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class ObjectArgument extends LiteralArgument
{
public function __construct(object $value)
{
parent::__construct($value, LiteralArgument::TYPE_OBJECT);
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument\Literal;
use League\Container\Argument\LiteralArgument;
class StringArgument extends LiteralArgument
{
public function __construct(string $value)
{
parent::__construct($value, LiteralArgument::TYPE_STRING);
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
use InvalidArgumentException;
class LiteralArgument implements LiteralArgumentInterface
{
public const TYPE_ARRAY = 'array';
public const TYPE_BOOL = 'boolean';
public const TYPE_BOOLEAN = 'boolean';
public const TYPE_CALLABLE = 'callable';
public const TYPE_DOUBLE = 'double';
public const TYPE_FLOAT = 'double';
public const TYPE_INT = 'integer';
public const TYPE_INTEGER = 'integer';
public const TYPE_OBJECT = 'object';
public const TYPE_STRING = 'string';
/**
* @var mixed
*/
protected $value;
public function __construct($value, ?string $type = null)
{
if (
null === $type
|| ($type === self::TYPE_CALLABLE && is_callable($value))
|| ($type === self::TYPE_OBJECT && is_object($value))
|| gettype($value) === $type
) {
$this->value = $value;
} else {
throw new InvalidArgumentException('Incorrect type for value.');
}
}
/**
* {@inheritdoc}
*/
public function getValue()
{
return $this->value;
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
interface LiteralArgumentInterface extends ArgumentInterface
{
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
class ResolvableArgument implements ResolvableArgumentInterface
{
protected $value;
public function __construct(string $value)
{
$this->value = $value;
}
public function getValue(): string
{
return $this->value;
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace League\Container\Argument;
interface ResolvableArgumentInterface extends ArgumentInterface
{
public function getValue(): string;
}

View File

@ -0,0 +1,210 @@
<?php
declare(strict_types=1);
namespace League\Container;
use League\Container\Definition\{DefinitionAggregate, DefinitionInterface, DefinitionAggregateInterface};
use League\Container\Exception\{NotFoundException, ContainerException};
use League\Container\Inflector\{InflectorAggregate, InflectorInterface, InflectorAggregateInterface};
use League\Container\ServiceProvider\{ServiceProviderAggregate,
ServiceProviderAggregateInterface,
ServiceProviderInterface};
use Psr\Container\ContainerInterface;
class Container implements DefinitionContainerInterface
{
/**
* @var boolean
*/
protected $defaultToShared = false;
/**
* @var DefinitionAggregateInterface
*/
protected $definitions;
/**
* @var ServiceProviderAggregateInterface
*/
protected $providers;
/**
* @var InflectorAggregateInterface
*/
protected $inflectors;
/**
* @var ContainerInterface[]
*/
protected $delegates = [];
public function __construct(
?DefinitionAggregateInterface $definitions = null,
?ServiceProviderAggregateInterface $providers = null,
?InflectorAggregateInterface $inflectors = null
) {
$this->definitions = $definitions ?? new DefinitionAggregate();
$this->providers = $providers ?? new ServiceProviderAggregate();
$this->inflectors = $inflectors ?? new InflectorAggregate();
if ($this->definitions instanceof ContainerAwareInterface) {
$this->definitions->setContainer($this);
}
if ($this->providers instanceof ContainerAwareInterface) {
$this->providers->setContainer($this);
}
if ($this->inflectors instanceof ContainerAwareInterface) {
$this->inflectors->setContainer($this);
}
}
public function add(string $id, $concrete = null): DefinitionInterface
{
$concrete = $concrete ?? $id;
if (true === $this->defaultToShared) {
return $this->addShared($id, $concrete);
}
return $this->definitions->add($id, $concrete);
}
public function addShared(string $id, $concrete = null): DefinitionInterface
{
$concrete = $concrete ?? $id;
return $this->definitions->addShared($id, $concrete);
}
public function defaultToShared(bool $shared = true): ContainerInterface
{
$this->defaultToShared = $shared;
return $this;
}
public function extend(string $id): DefinitionInterface
{
if ($this->providers->provides($id)) {
$this->providers->register($id);
}
if ($this->definitions->has($id)) {
return $this->definitions->getDefinition($id);
}
throw new NotFoundException(sprintf(
'Unable to extend alias (%s) as it is not being managed as a definition',
$id
));
}
public function addServiceProvider(ServiceProviderInterface $provider): DefinitionContainerInterface
{
$this->providers->add($provider);
return $this;
}
/**
* @template RequestedType
*
* @param class-string<RequestedType>|string $id
*
* @return RequestedType|mixed
*/
public function get($id)
{
return $this->resolve($id);
}
/**
* @template RequestedType
*
* @param class-string<RequestedType>|string $id
*
* @return RequestedType|mixed
*/
public function getNew($id)
{
return $this->resolve($id, true);
}
public function has($id): bool
{
if ($this->definitions->has($id)) {
return true;
}
if ($this->definitions->hasTag($id)) {
return true;
}
if ($this->providers->provides($id)) {
return true;
}
foreach ($this->delegates as $delegate) {
if ($delegate->has($id)) {
return true;
}
}
return false;
}
public function inflector(string $type, ?callable $callback = null): InflectorInterface
{
return $this->inflectors->add($type, $callback);
}
public function delegate(ContainerInterface $container): self
{
$this->delegates[] = $container;
if ($container instanceof ContainerAwareInterface) {
$container->setContainer($this);
}
return $this;
}
protected function resolve($id, bool $new = false)
{
if ($this->definitions->has($id)) {
$resolved = (true === $new) ? $this->definitions->resolveNew($id) : $this->definitions->resolve($id);
return $this->inflectors->inflect($resolved);
}
if ($this->definitions->hasTag($id)) {
$arrayOf = (true === $new)
? $this->definitions->resolveTaggedNew($id)
: $this->definitions->resolveTagged($id);
array_walk($arrayOf, function (&$resolved) {
$resolved = $this->inflectors->inflect($resolved);
});
return $arrayOf;
}
if ($this->providers->provides($id)) {
$this->providers->register($id);
if (!$this->definitions->has($id) && !$this->definitions->hasTag($id)) {
throw new ContainerException(sprintf('Service provider lied about providing (%s) service', $id));
}
return $this->resolve($id, $new);
}
foreach ($this->delegates as $delegate) {
if ($delegate->has($id)) {
$resolved = $delegate->get($id);
return $this->inflectors->inflect($resolved);
}
}
throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id));
}
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Container;
interface ContainerAwareInterface
{
public function getContainer(): DefinitionContainerInterface;
public function setContainer(DefinitionContainerInterface $container): ContainerAwareInterface;
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace League\Container;
use BadMethodCallException;
use League\Container\Exception\ContainerException;
trait ContainerAwareTrait
{
/**
* @var ?DefinitionContainerInterface
*/
protected $container;
public function setContainer(DefinitionContainerInterface $container): ContainerAwareInterface
{
$this->container = $container;
if ($this instanceof ContainerAwareInterface) {
return $this;
}
throw new BadMethodCallException(sprintf(
'Attempt to use (%s) while not implementing (%s)',
ContainerAwareTrait::class,
ContainerAwareInterface::class
));
}
public function getContainer(): DefinitionContainerInterface
{
if ($this->container instanceof DefinitionContainerInterface) {
return $this->container;
}
throw new ContainerException('No container implementation has been set.');
}
}

View File

@ -0,0 +1,242 @@
<?php
declare(strict_types=1);
namespace League\Container\Definition;
use League\Container\Argument\{
ArgumentResolverInterface,
ArgumentResolverTrait,
ArgumentInterface,
LiteralArgumentInterface
};
use League\Container\ContainerAwareTrait;
use League\Container\Exception\ContainerException;
use Psr\Container\ContainerInterface;
use ReflectionClass;
class Definition implements ArgumentResolverInterface, DefinitionInterface
{
use ArgumentResolverTrait;
use ContainerAwareTrait;
/**
* @var string
*/
protected $alias;
/**
* @var mixed
*/
protected $concrete;
/**
* @var boolean
*/
protected $shared = false;
/**
* @var array
*/
protected $tags = [];
/**
* @var array
*/
protected $arguments = [];
/**
* @var array
*/
protected $methods = [];
/**
* @var mixed
*/
protected $resolved;
/**
* @param string $id
* @param mixed|null $concrete
*/
public function __construct(string $id, $concrete = null)
{
$id = static::normaliseAlias($id);
$concrete = $concrete ?? $id;
$this->alias = $id;
$this->concrete = $concrete;
}
public function addTag(string $tag): DefinitionInterface
{
$this->tags[$tag] = true;
return $this;
}
public function hasTag(string $tag): bool
{
return isset($this->tags[$tag]);
}
public function setAlias(string $id): DefinitionInterface
{
$id = static::normaliseAlias($id);
$this->alias = $id;
return $this;
}
public function getAlias(): string
{
return $this->alias;
}
public function setShared(bool $shared = true): DefinitionInterface
{
$this->shared = $shared;
return $this;
}
public function isShared(): bool
{
return $this->shared;
}
public function getConcrete()
{
return $this->concrete;
}
public function setConcrete($concrete): DefinitionInterface
{
$this->concrete = $concrete;
$this->resolved = null;
return $this;
}
public function addArgument($arg): DefinitionInterface
{
$this->arguments[] = $arg;
return $this;
}
public function addArguments(array $args): DefinitionInterface
{
foreach ($args as $arg) {
$this->addArgument($arg);
}
return $this;
}
public function addMethodCall(string $method, array $args = []): DefinitionInterface
{
$this->methods[] = [
'method' => $method,
'arguments' => $args
];
return $this;
}
public function addMethodCalls(array $methods = []): DefinitionInterface
{
foreach ($methods as $method => $args) {
$this->addMethodCall($method, $args);
}
return $this;
}
public function resolve()
{
if (null !== $this->resolved && $this->isShared()) {
return $this->resolved;
}
return $this->resolveNew();
}
public function resolveNew()
{
$concrete = $this->concrete;
if (is_callable($concrete)) {
$concrete = $this->resolveCallable($concrete);
}
if ($concrete instanceof LiteralArgumentInterface) {
$this->resolved = $concrete->getValue();
return $concrete->getValue();
}
if ($concrete instanceof ArgumentInterface) {
$concrete = $concrete->getValue();
}
if (is_string($concrete)) {
if (class_exists($concrete)) {
$concrete = $this->resolveClass($concrete);
} elseif ($this->getAlias() === $concrete) {
return $concrete;
}
}
if (is_object($concrete)) {
$concrete = $this->invokeMethods($concrete);
}
try {
$container = $this->getContainer();
} catch (ContainerException $e) {
$container = null;
}
// if we still have a string, try to pull it from the container
// this allows for `alias -> alias -> ... -> concrete
if (is_string($concrete) && $container instanceof ContainerInterface && $container->has($concrete)) {
$concrete = $container->get($concrete);
}
$this->resolved = $concrete;
return $concrete;
}
/**
* @param callable $concrete
* @return mixed
*/
protected function resolveCallable(callable $concrete)
{
$resolved = $this->resolveArguments($this->arguments);
return call_user_func_array($concrete, $resolved);
}
protected function resolveClass(string $concrete): object
{
$resolved = $this->resolveArguments($this->arguments);
$reflection = new ReflectionClass($concrete);
return $reflection->newInstanceArgs($resolved);
}
protected function invokeMethods(object $instance): object
{
foreach ($this->methods as $method) {
$args = $this->resolveArguments($method['arguments']);
$callable = [$instance, $method['method']];
call_user_func_array($callable, $args);
}
return $instance;
}
public static function normaliseAlias(string $alias): string
{
if (strpos($alias, '\\') === 0) {
return substr($alias, 1);
}
return $alias;
}
}

View File

@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace League\Container\Definition;
use Generator;
use League\Container\ContainerAwareTrait;
use League\Container\Exception\NotFoundException;
class DefinitionAggregate implements DefinitionAggregateInterface
{
use ContainerAwareTrait;
/**
* @var DefinitionInterface[]
*/
protected $definitions = [];
public function __construct(array $definitions = [])
{
$this->definitions = array_filter($definitions, static function ($definition) {
return ($definition instanceof DefinitionInterface);
});
}
public function add(string $id, $definition): DefinitionInterface
{
if (false === ($definition instanceof DefinitionInterface)) {
$definition = new Definition($id, $definition);
}
$this->definitions[] = $definition->setAlias($id);
return $definition;
}
public function addShared(string $id, $definition): DefinitionInterface
{
$definition = $this->add($id, $definition);
return $definition->setShared(true);
}
public function has(string $id): bool
{
$id = Definition::normaliseAlias($id);
foreach ($this->getIterator() as $definition) {
if ($id === $definition->getAlias()) {
return true;
}
}
return false;
}
public function hasTag(string $tag): bool
{
foreach ($this->getIterator() as $definition) {
if ($definition->hasTag($tag)) {
return true;
}
}
return false;
}
public function getDefinition(string $id): DefinitionInterface
{
$id = Definition::normaliseAlias($id);
foreach ($this->getIterator() as $definition) {
if ($id === $definition->getAlias()) {
return $definition->setContainer($this->getContainer());
}
}
throw new NotFoundException(sprintf('Alias (%s) is not being handled as a definition.', $id));
}
public function resolve(string $id)
{
return $this->getDefinition($id)->resolve();
}
public function resolveNew(string $id)
{
return $this->getDefinition($id)->resolveNew();
}
public function resolveTagged(string $tag): array
{
$arrayOf = [];
foreach ($this->getIterator() as $definition) {
if ($definition->hasTag($tag)) {
$arrayOf[] = $definition->setContainer($this->getContainer())->resolve();
}
}
return $arrayOf;
}
public function resolveTaggedNew(string $tag): array
{
$arrayOf = [];
foreach ($this->getIterator() as $definition) {
if ($definition->hasTag($tag)) {
$arrayOf[] = $definition->setContainer($this->getContainer())->resolveNew();
}
}
return $arrayOf;
}
public function getIterator(): Generator
{
yield from $this->definitions;
}
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace League\Container\Definition;
use IteratorAggregate;
use League\Container\ContainerAwareInterface;
interface DefinitionAggregateInterface extends ContainerAwareInterface, IteratorAggregate
{
public function add(string $id, $definition): DefinitionInterface;
public function addShared(string $id, $definition): DefinitionInterface;
public function getDefinition(string $id): DefinitionInterface;
public function has(string $id): bool;
public function hasTag(string $tag): bool;
public function resolve(string $id);
public function resolveNew(string $id);
public function resolveTagged(string $tag): array;
public function resolveTaggedNew(string $tag): array;
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace League\Container\Definition;
use League\Container\ContainerAwareInterface;
interface DefinitionInterface extends ContainerAwareInterface
{
public function addArgument($arg): DefinitionInterface;
public function addArguments(array $args): DefinitionInterface;
public function addMethodCall(string $method, array $args = []): DefinitionInterface;
public function addMethodCalls(array $methods = []): DefinitionInterface;
public function addTag(string $tag): DefinitionInterface;
public function getAlias(): string;
public function getConcrete();
public function hasTag(string $tag): bool;
public function isShared(): bool;
public function resolve();
public function resolveNew();
public function setAlias(string $id): DefinitionInterface;
public function setConcrete($concrete): DefinitionInterface;
public function setShared(bool $shared): DefinitionInterface;
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace League\Container;
use League\Container\Definition\DefinitionInterface;
use League\Container\Inflector\InflectorInterface;
use League\Container\ServiceProvider\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
interface DefinitionContainerInterface extends ContainerInterface
{
public function add(string $id, $concrete = null): DefinitionInterface;
public function addServiceProvider(ServiceProviderInterface $provider): self;
public function addShared(string $id, $concrete = null): DefinitionInterface;
public function extend(string $id): DefinitionInterface;
public function getNew($id);
public function inflector(string $type, ?callable $callback = null): InflectorInterface;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace League\Container\Exception;
use Psr\Container\ContainerExceptionInterface;
use RuntimeException;
class ContainerException extends RuntimeException implements ContainerExceptionInterface
{
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace League\Container\Exception;
use Psr\Container\NotFoundExceptionInterface;
use InvalidArgumentException;
class NotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface
{
}

View File

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace League\Container\Inflector;
use League\Container\Argument\ArgumentResolverInterface;
use League\Container\Argument\ArgumentResolverTrait;
use League\Container\ContainerAwareTrait;
class Inflector implements ArgumentResolverInterface, InflectorInterface
{
use ArgumentResolverTrait;
use ContainerAwareTrait;
/**
* @var string
*/
protected $type;
/**
* @var callable|null
*/
protected $callback;
/**
* @var array
*/
protected $methods = [];
/**
* @var array
*/
protected $properties = [];
public function __construct(string $type, ?callable $callback = null)
{
$this->type = $type;
$this->callback = $callback;
}
public function getType(): string
{
return $this->type;
}
public function invokeMethod(string $name, array $args): InflectorInterface
{
$this->methods[$name] = $args;
return $this;
}
public function invokeMethods(array $methods): InflectorInterface
{
foreach ($methods as $name => $args) {
$this->invokeMethod($name, $args);
}
return $this;
}
public function setProperty(string $property, $value): InflectorInterface
{
$this->properties[$property] = $this->resolveArguments([$value])[0];
return $this;
}
public function setProperties(array $properties): InflectorInterface
{
foreach ($properties as $property => $value) {
$this->setProperty($property, $value);
}
return $this;
}
public function inflect(object $object): void
{
$properties = $this->resolveArguments(array_values($this->properties));
$properties = array_combine(array_keys($this->properties), $properties);
// array_combine() can technically return false
foreach ($properties ?: [] as $property => $value) {
$object->{$property} = $value;
}
foreach ($this->methods as $method => $args) {
$args = $this->resolveArguments($args);
$callable = [$object, $method];
call_user_func_array($callable, $args);
}
if ($this->callback !== null) {
call_user_func($this->callback, $object);
}
}
}

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace League\Container\Inflector;
use Generator;
use League\Container\ContainerAwareTrait;
class InflectorAggregate implements InflectorAggregateInterface
{
use ContainerAwareTrait;
/**
* @var Inflector[]
*/
protected $inflectors = [];
public function add(string $type, ?callable $callback = null): Inflector
{
$inflector = new Inflector($type, $callback);
$this->inflectors[] = $inflector;
return $inflector;
}
public function inflect($object)
{
foreach ($this->getIterator() as $inflector) {
$type = $inflector->getType();
if ($object instanceof $type) {
$inflector->setContainer($this->getContainer());
$inflector->inflect($object);
}
}
return $object;
}
public function getIterator(): Generator
{
yield from $this->inflectors;
}
}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace League\Container\Inflector;
use IteratorAggregate;
use League\Container\ContainerAwareInterface;
interface InflectorAggregateInterface extends ContainerAwareInterface, IteratorAggregate
{
public function add(string $type, ?callable $callback = null): Inflector;
public function inflect(object $object);
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\Inflector;
interface InflectorInterface
{
public function getType(): string;
public function inflect(object $object): void;
public function invokeMethod(string $name, array $args): InflectorInterface;
public function invokeMethods(array $methods): InflectorInterface;
public function setProperties(array $properties): InflectorInterface;
public function setProperty(string $property, $value): InflectorInterface;
}

View File

@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace League\Container;
use League\Container\Argument\{ArgumentResolverInterface, ArgumentResolverTrait};
use League\Container\Exception\ContainerException;
use League\Container\Exception\NotFoundException;
use Psr\Container\ContainerInterface;
use ReflectionClass;
use ReflectionFunction;
use ReflectionMethod;
class ReflectionContainer implements ArgumentResolverInterface, ContainerInterface
{
use ArgumentResolverTrait;
use ContainerAwareTrait;
/**
* @var boolean
*/
protected $cacheResolutions;
/**
* @var array
*/
protected $cache = [];
public function __construct(bool $cacheResolutions = false)
{
$this->cacheResolutions = $cacheResolutions;
}
public function get($id, array $args = [])
{
if ($this->cacheResolutions === true && array_key_exists($id, $this->cache)) {
return $this->cache[$id];
}
if (!$this->has($id)) {
throw new NotFoundException(
sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id)
);
}
$reflector = new ReflectionClass($id);
$construct = $reflector->getConstructor();
if ($construct && !$construct->isPublic()) {
throw new NotFoundException(
sprintf('Alias (%s) has a non-public constructor and therefore cannot be instantiated', $id)
);
}
$resolution = $construct === null
? new $id()
: $reflector->newInstanceArgs($this->reflectArguments($construct, $args))
;
if ($this->cacheResolutions === true) {
$this->cache[$id] = $resolution;
}
return $resolution;
}
public function has($id): bool
{
return class_exists($id);
}
public function call(callable $callable, array $args = [])
{
if (is_string($callable) && strpos($callable, '::') !== false) {
$callable = explode('::', $callable);
}
if (is_array($callable)) {
if (is_string($callable[0])) {
// if we have a definition container, try that first, otherwise, reflect
try {
$callable[0] = $this->getContainer()->get($callable[0]);
} catch (ContainerException $e) {
$callable[0] = $this->get($callable[0]);
}
}
$reflection = new ReflectionMethod($callable[0], $callable[1]);
if ($reflection->isStatic()) {
$callable[0] = null;
}
return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args));
}
if (is_object($callable)) {
$reflection = new ReflectionMethod($callable, '__invoke');
return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args));
}
$reflection = new ReflectionFunction(\Closure::fromCallable($callable));
return $reflection->invokeArgs($this->reflectArguments($reflection, $args));
}
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace League\Container\ServiceProvider;
use League\Container\ContainerAwareTrait;
abstract class AbstractServiceProvider implements ServiceProviderInterface
{
use ContainerAwareTrait;
/**
* @var string
*/
protected $identifier;
public function getIdentifier(): string
{
return $this->identifier ?? get_class($this);
}
public function setIdentifier(string $id): ServiceProviderInterface
{
$this->identifier = $id;
return $this;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace League\Container\ServiceProvider;
interface BootableServiceProviderInterface extends ServiceProviderInterface
{
/**
* Method will be invoked on registration of a service provider implementing
* this interface. Provides ability for eager loading of Service Providers.
*
* @return void
*/
public function boot(): void;
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace League\Container\ServiceProvider;
use Generator;
use League\Container\Exception\ContainerException;
use League\Container\{ContainerAwareInterface, ContainerAwareTrait};
class ServiceProviderAggregate implements ServiceProviderAggregateInterface
{
use ContainerAwareTrait;
/**
* @var ServiceProviderInterface[]
*/
protected $providers = [];
/**
* @var array
*/
protected $registered = [];
public function add(ServiceProviderInterface $provider): ServiceProviderAggregateInterface
{
if (in_array($provider, $this->providers, true)) {
return $this;
}
$provider->setContainer($this->getContainer());
if ($provider instanceof BootableServiceProviderInterface) {
$provider->boot();
}
$this->providers[] = $provider;
return $this;
}
public function provides(string $service): bool
{
foreach ($this->getIterator() as $provider) {
if ($provider->provides($service)) {
return true;
}
}
return false;
}
public function getIterator(): Generator
{
yield from $this->providers;
}
public function register(string $service): void
{
if (false === $this->provides($service)) {
throw new ContainerException(
sprintf('(%s) is not provided by a service provider', $service)
);
}
foreach ($this->getIterator() as $provider) {
if (in_array($provider->getIdentifier(), $this->registered, true)) {
continue;
}
if ($provider->provides($service)) {
$provider->register();
$this->registered[] = $provider->getIdentifier();
}
}
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\ServiceProvider;
use IteratorAggregate;
use League\Container\ContainerAwareInterface;
interface ServiceProviderAggregateInterface extends ContainerAwareInterface, IteratorAggregate
{
public function add(ServiceProviderInterface $provider): ServiceProviderAggregateInterface;
public function provides(string $id): bool;
public function register(string $service): void;
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace League\Container\ServiceProvider;
use League\Container\ContainerAwareInterface;
interface ServiceProviderInterface extends ContainerAwareInterface
{
public function getIdentifier(): string;
public function provides(string $id): bool;
public function register(): void;
public function setIdentifier(string $id): ServiceProviderInterface;
}