From ac0c155f19bb2a6645ae4d72e4e58f9b1f444580 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 15 Feb 2024 13:31:23 +0200 Subject: [PATCH 1/3] Add checking parent scopes --- src/Core/src/Internal/Factory.php | 9 ++++++- src/Core/tests/Scope/ScopeAttributeTest.php | 27 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Internal/Factory.php b/src/Core/src/Internal/Factory.php index 06e409b82..33d3b839a 100644 --- a/src/Core/src/Internal/Factory.php +++ b/src/Core/src/Internal/Factory.php @@ -372,7 +372,14 @@ private function validateNewInstance( $ctx->reflection = new \ReflectionClass($instance); $scopeName = ($ctx->reflection->getAttributes(ScopeAttribute::class)[0] ?? null)?->newInstance()->name; if ($scopeName !== null && $scopeName !== $this->scope->getScopeName()) { - throw new BadScopeException($scopeName, $instance::class); + $parent = $this->scope->getParentScope(); + while ($parent !== null) { + if ($correctScope = $parent->getScopeName() === $scopeName) { + break; + } + $parent = $parent->getParentScope(); + } + ($correctScope ?? false) === true or throw new BadScopeException($scopeName, $instance::class); } return $arguments === [] diff --git a/src/Core/tests/Scope/ScopeAttributeTest.php b/src/Core/tests/Scope/ScopeAttributeTest.php index 7fbb684e6..8a4f14a5e 100644 --- a/src/Core/tests/Scope/ScopeAttributeTest.php +++ b/src/Core/tests/Scope/ScopeAttributeTest.php @@ -43,6 +43,33 @@ public function testNamedScopeResolveFromRootInNullScope(): void }, name: 'foo'); } + public function testNamedScopeResolveFromParentScope(): void + { + $root = new Container(); + $root->getBinder('bar')->bindSingleton('binding', static fn () => new AttrScopeFoo()); + + $root->runScoped(static function (Container $fooScope) { + $fooScope->runScoped(static function (Container $container) { + self::assertInstanceOf(AttrScopeFoo::class, $container->get('binding')); + }, name: 'bar'); + }, name: 'foo'); + } + + public function testBadScopeExceptionAllParentNamedScopesNotContainsNeededScope(): void + { + self::expectException(BadScopeException::class); + self::expectExceptionMessage('`foo`'); + + $root = new Container(); + $root->getBinder('bar')->bindSingleton('binding', static fn () => new AttrScopeFoo()); + + $root->runScoped(static function (Container $fooScope) { + $fooScope->runScoped(static function (Container $container) { + self::assertInstanceOf(AttrScopeFoo::class, $container->get('binding')); + }, name: 'bar'); + }, name: 'baz'); + } + /** * Request a dependency from a correct scope using alias but there is no any binding for this alias in the scope. * The binding can be in the parent scope, but it doesn't matter. From 0f48c6bedb332515a0a36a114893682d1d9da504 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 15 Feb 2024 13:38:23 +0200 Subject: [PATCH 2/3] Fix Psalm issues --- src/Exceptions/src/Renderer/ConsoleRenderer.php | 2 +- src/Security/src/RulesInterface.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Exceptions/src/Renderer/ConsoleRenderer.php b/src/Exceptions/src/Renderer/ConsoleRenderer.php index 61a1227ff..25487b378 100644 --- a/src/Exceptions/src/Renderer/ConsoleRenderer.php +++ b/src/Exceptions/src/Renderer/ConsoleRenderer.php @@ -41,7 +41,7 @@ class ConsoleRenderer extends AbstractRenderer private bool $colorsSupport; /** - * @param bool|resource $stream + * @param bool|resource|null $stream */ public function __construct(mixed $stream = null) { diff --git a/src/Security/src/RulesInterface.php b/src/Security/src/RulesInterface.php index 8bbea55b5..7c93b3d5f 100644 --- a/src/Security/src/RulesInterface.php +++ b/src/Security/src/RulesInterface.php @@ -23,9 +23,9 @@ interface RulesInterface * * Technically you can use this method as you use container bindings. * - * @param string $name Rule name in a string form. - * @param string|array|callable|RuleInterface $rule Rule, if kept as null rule name must be - * treated as class name for RuleInterface. + * @param string $name Rule name in a string form. + * @param string|array|callable|RuleInterface|null $rule Rule, if kept as null rule name must be treated as class + * name for RuleInterface. * @throws RuleException */ public function set(string $name, mixed $rule = null): self; From 03fda062e14bc93764c8c06a221041b869c96c57 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Thu, 15 Feb 2024 22:19:51 +0400 Subject: [PATCH 3/3] Simplify code --- src/Core/src/Internal/Factory.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Core/src/Internal/Factory.php b/src/Core/src/Internal/Factory.php index 33d3b839a..636d896fe 100644 --- a/src/Core/src/Internal/Factory.php +++ b/src/Core/src/Internal/Factory.php @@ -371,15 +371,11 @@ private function validateNewInstance( // Check scope name $ctx->reflection = new \ReflectionClass($instance); $scopeName = ($ctx->reflection->getAttributes(ScopeAttribute::class)[0] ?? null)?->newInstance()->name; - if ($scopeName !== null && $scopeName !== $this->scope->getScopeName()) { - $parent = $this->scope->getParentScope(); - while ($parent !== null) { - if ($correctScope = $parent->getScopeName() === $scopeName) { - break; - } - $parent = $parent->getParentScope(); + if ($scopeName !== null) { + $scope = $this->scope; + while ($scope->getScopeName() !== $scopeName) { + $scope = $scope->getParentScope() ?? throw new BadScopeException($scopeName, $instance::class); } - ($correctScope ?? false) === true or throw new BadScopeException($scopeName, $instance::class); } return $arguments === []