Skip to content

Commit

Permalink
Merge pull request #1076: [spiral/core] deep scope name matching when…
Browse files Browse the repository at this point in the history
… the Scope attribute is used
  • Loading branch information
roxblnfk committed Feb 15, 2024
2 parents dfb4061 + ed83d80 commit 96cf3f3
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/Core/src/Internal/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,11 @@ private function validateNewInstance(
// Check scope name
$ctx->reflection = new \ReflectionClass($instance);
$scopeName = ($ctx->reflection->getAttributes(Attribute\Scope::class)[0] ?? null)?->newInstance()->name;
if ($scopeName !== null && $scopeName !== $this->scope->getScopeName()) {
throw new BadScopeException($scopeName, $instance::class);
if ($scopeName !== null) {
$scope = $this->scope;
while ($scope->getScopeName() !== $scopeName) {
$scope = $scope->getParentScope() ?? throw new BadScopeException($scopeName, $instance::class);
}
}

return $arguments === []
Expand Down
27 changes: 27 additions & 0 deletions src/Core/tests/Scope/ScopeAttributeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/Exceptions/src/Renderer/ConsoleRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Security/src/RulesInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 96cf3f3

Please sign in to comment.