From 43912d35ec831006e94c127b1113b20b08dadda7 Mon Sep 17 00:00:00 2001 From: yiiliveext Date: Wed, 17 Nov 2021 22:06:09 +0200 Subject: [PATCH] Move DefinitionStorage (#269) Co-authored-by: Alexander Makarov --- src/Container.php | 5 +- src/DefinitionStorage.php | 204 ------------------ .../ServiceWithBuiltinTypeWithoutDefault.php | 12 -- .../ServiceWithNonExistingDependency.php | 12 -- .../ServiceWithNonExistingSubDependency.php | 12 -- .../ServiceWithNonResolvableUnionTypes.php | 12 -- .../ServiceWithPrivateConstructor.php | 12 -- ...iceWithPrivateConstructorSubDependency.php | 12 -- tests/Unit/DefinitionStorageTest.php | 114 ---------- 9 files changed, 3 insertions(+), 392 deletions(-) delete mode 100644 src/DefinitionStorage.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithBuiltinTypeWithoutDefault.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithNonExistingDependency.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithNonExistingSubDependency.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithNonResolvableUnionTypes.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithPrivateConstructor.php delete mode 100644 tests/Support/DefinitionStorage/ServiceWithPrivateConstructorSubDependency.php delete mode 100644 tests/Unit/DefinitionStorageTest.php diff --git a/src/Container.php b/src/Container.php index 6c6e9ded..d08de20b 100644 --- a/src/Container.php +++ b/src/Container.php @@ -7,13 +7,14 @@ use Closure; use InvalidArgumentException; use Psr\Container\ContainerInterface; -use Yiisoft\Definitions\Infrastructure\DefinitionValidator; -use Yiisoft\Di\Contracts\ServiceProviderInterface; use Yiisoft\Definitions\ArrayDefinition; use Yiisoft\Definitions\Exception\CircularReferenceException; use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotFoundException; use Yiisoft\Definitions\Exception\NotInstantiableException; +use Yiisoft\Definitions\Infrastructure\DefinitionValidator; +use Yiisoft\Definitions\Infrastructure\DefinitionStorage; +use Yiisoft\Di\Contracts\ServiceProviderInterface; use function array_key_exists; use function array_keys; diff --git a/src/DefinitionStorage.php b/src/DefinitionStorage.php deleted file mode 100644 index 73fff8ab..00000000 --- a/src/DefinitionStorage.php +++ /dev/null @@ -1,204 +0,0 @@ -definitions = $definitions; - } - - public function setDelegateContainer(ContainerInterface $delegateContainer): void - { - $this->delegateContainer = $delegateContainer; - } - - /** - * Checks if there is a definition with ID specified and that it can be created. - * - * @param string $id class name, interface name or alias name - * - * @throws CircularReferenceException - */ - public function has(string $id): bool - { - $this->buildStack = []; - return $this->isResolvable($id, []); - } - - public function getBuildStack(): array - { - return $this->buildStack; - } - - /** - * Get a definition with a given ID. - * - * @return mixed|object Definition with a given ID. - */ - public function get(string $id) - { - if (!isset($this->definitions[$id])) { - throw new RuntimeException("Service $id doesn't exist in DefinitionStorage."); - } - return $this->definitions[$id]; - } - - /** - * Set a definition. - * - * @param string $id ID to set definition for. - * @param mixed|object $definition Definition to set. - */ - public function set(string $id, $definition): void - { - $this->definitions[$id] = $definition; - } - - private function isResolvable(string $id, array $building): bool - { - if (isset($this->definitions[$id])) { - return true; - } - - if (!class_exists($id)) { - $this->buildStack += $building + [$id => 1]; - return false; - } - - if (isset($building[$id])) { - throw new CircularReferenceException(sprintf( - 'Circular reference to "%s" detected while building: %s.', - $id, - implode(', ', array_keys($building)) - )); - } - - try { - $dependencies = DefinitionExtractor::getInstance()->fromClassName($id); - } catch (Throwable $e) { - $this->buildStack += $building + [$id => 1]; - return false; - } - - if ($dependencies === []) { - $this->definitions[$id] = $id; - return true; - } - - $isResolvable = true; - $building[$id] = 1; - - try { - foreach ($dependencies as $dependency) { - $parameter = $dependency->getReflection(); - $type = $parameter->getType(); - - if ($parameter->isVariadic() || $parameter->isOptional()) { - break; - } - - /** - * @var ReflectionNamedType|ReflectionUnionType|null $type - * @psalm-suppress RedundantConditionGivenDocblockType - * @psalm-suppress UndefinedClass - */ - if ($type === null || (!$type instanceof ReflectionUnionType && $type->isBuiltin())) { - $isResolvable = false; - break; - } - - // PHP 8 union type is used as type hint - /** @psalm-suppress UndefinedClass, TypeDoesNotContainType */ - if ($type instanceof ReflectionUnionType) { - $isUnionTypeResolvable = false; - $unionTypes = []; - /** @var ReflectionNamedType $unionType */ - foreach ($type->getTypes() as $unionType) { - if (!$unionType->isBuiltin()) { - $typeName = $unionType->getName(); - if ($typeName === 'self') { - continue; - } - $unionTypes[] = $typeName; - if ($this->isResolvable($typeName, $building)) { - $isUnionTypeResolvable = true; - break; - } - } - } - - - if (!$isUnionTypeResolvable) { - foreach ($unionTypes as $typeName) { - if ($this->delegateContainer !== null && $this->delegateContainer->has($typeName)) { - $isUnionTypeResolvable = true; - break; - } - } - - $isResolvable = $isUnionTypeResolvable; - if (!$isResolvable) { - break; - } - } - continue; - } - - /** @var ReflectionNamedType|null $type */ - // Our parameter has a class type hint - if ($type !== null && !$type->isBuiltin()) { - $typeName = $type->getName(); - /** - * @psalm-suppress TypeDoesNotContainType - * - * @link https://github.com/vimeo/psalm/issues/6756 - */ - if ($typeName === 'self') { - throw new CircularReferenceException(sprintf( - 'Circular reference to "%s" detected while building: %s.', - $id, - implode(', ', array_keys($building)) - )); - } - - /** @psalm-suppress RedundantPropertyInitializationCheck */ - if (!$this->isResolvable($typeName, $building) && ($this->delegateContainer === null || !$this->delegateContainer->has($typeName))) { - $isResolvable = false; - break; - } - } - } - } finally { - $this->buildStack += $building; - unset($building[$id]); - } - - if ($isResolvable) { - $this->definitions[$id] = $id; - } - - return $isResolvable; - } -} diff --git a/tests/Support/DefinitionStorage/ServiceWithBuiltinTypeWithoutDefault.php b/tests/Support/DefinitionStorage/ServiceWithBuiltinTypeWithoutDefault.php deleted file mode 100644 index e5b884ec..00000000 --- a/tests/Support/DefinitionStorage/ServiceWithBuiltinTypeWithoutDefault.php +++ /dev/null @@ -1,12 +0,0 @@ - 'anything']); - $this->assertTrue($storage->has('existing')); - $this->assertSame([], $storage->getBuildStack()); - } - - public function testNonExistingService(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(\NonExisitng::class)); - $this->assertSame([\NonExisitng::class => 1], $storage->getBuildStack()); - } - - public function testServiceWithNonExistingDependency(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithNonExistingDependency::class)); - $this->assertSame( - [ - ServiceWithNonExistingDependency::class => 1, - \NonExisting::class => 1, - ], - $storage->getBuildStack() - ); - } - - public function testServiceWithNonExistingSubDependency(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithNonExistingSubDependency::class)); - $this->assertSame( - [ - ServiceWithNonExistingSubDependency::class => 1, - ServiceWithNonExistingDependency::class => 1, - \NonExisting::class => 1, - ], - $storage->getBuildStack() - ); - } - - public function testServiceWithPrivateConstructor(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithPrivateConstructor::class)); - $this->assertSame([ServiceWithPrivateConstructor::class => 1], $storage->getBuildStack()); - } - - public function testServiceWithPrivateConstructorSubDependency(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithPrivateConstructorSubDependency::class)); - $this->assertSame( - [ - ServiceWithPrivateConstructorSubDependency::class => 1, - ServiceWithPrivateConstructor::class => 1, - ], - $storage->getBuildStack() - ); - } - - public function testServiceWithBuiltInTypeWithoutDefault(): void - { - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithBuiltinTypeWithoutDefault::class)); - $this->assertSame([ServiceWithBuiltinTypeWithoutDefault::class => 1], $storage->getBuildStack()); - } - - public function testEmptyDelegateContainer(): void - { - $container = new Container([]); - $storage = new DefinitionStorage([]); - $storage->setDelegateContainer($container); - $this->assertFalse($storage->has(\NonExisitng::class)); - $this->assertSame([\NonExisitng::class => 1], $storage->getBuildStack()); - } - - public function testServiceWithNonExistingUnionTypes(): void - { - if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Union types are supported by PHP 8+ only.'); - } - - $storage = new DefinitionStorage([]); - $this->assertFalse($storage->has(ServiceWithNonResolvableUnionTypes::class)); - $this->assertSame( - [ - ServiceWithNonResolvableUnionTypes::class => 1, - ServiceWithNonExistingDependency::class => 1, - \NonExisting::class => 1, - ServiceWithPrivateConstructor::class => 1, - ], - $storage->getBuildStack() - ); - } -}