Skip to content

Commit

Permalink
Detect Proxy recursion when the proxy was configured as singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk committed Oct 21, 2024
1 parent 6bd3776 commit b6fe429
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 8 deletions.
19 changes: 12 additions & 7 deletions src/Core/src/Internal/Proxy/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,25 @@ public static function resolve(
);
}

if (!Proxy::isProxy($result)) {
return $result;
}

/**
* If we got a Proxy again, that we should retry with the new context
* to try to get the instance from the Proxy Fallback Factory.
* If there is no the Proxy Fallback Factory, {@see RecursiveProxyException} will be thrown.
*/
if (Proxy::isProxy($result)) {
try {
return $c->get($alias, new RetryContext($context));
} catch (RecursiveProxyException $e) {
throw new RecursiveProxyException($e->alias, $e->bindingScope, self::getScope($c));
}
try {
$result = $c->get($alias, new RetryContext($context));
} catch (RecursiveProxyException $e) {
throw new RecursiveProxyException($e->alias, $e->bindingScope, self::getScope($c));
}

return $result;
// If Container returned a Proxy after the retry, then we have a recursion.
return Proxy::isProxy($result)
? throw new RecursiveProxyException($alias, null, self::getScope($c))
: $result;
}

/**
Expand Down
24 changes: 23 additions & 1 deletion src/Core/tests/Scope/ProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ public function __toString(): string
/**
* Proxy gets a proxy of the same type.
*/
public function testRecursiveProxy(): void
public function testRecursiveProxyNotSingleton(): void
{
$root = new Container();
$root->bind(UserInterface::class, new ProxyConfig(UserInterface::class));
Expand All @@ -322,6 +322,28 @@ public function testRecursiveProxy(): void
);
}

/**
* Proxy gets a proxy of the same type as a singleton.
*/
public function testRecursiveProxySingleton(): void
{
$root = new Container();
$root->bind(UserInterface::class, new ProxyConfig(UserInterface::class, singleton: true));

$this->expectException(RecursiveProxyException::class);
$this->expectExceptionMessage(
<<<MSG
Recursive proxy detected for `Spiral\Tests\Core\Scope\Stub\UserInterface`.
Calling scope: `root.null`.
MSG,
);

$root->runScope(
new Scope(),
fn(#[Proxy] UserInterface $user) => $user->getName(),
);
}

/**
* The {@see ContainerScope::runScope} ignores Container Proxy to avoid recursion.
*/
Expand Down

0 comments on commit b6fe429

Please sign in to comment.