Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interceptors polishing #1128

Merged
merged 3 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/Hmvc/src/CompatiblePipelineBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*
* @deprecated Use {@see PipelineBuilder} instead.
*/
class CompatiblePipelineBuilder implements PipelineBuilderInterface
final class CompatiblePipelineBuilder implements PipelineBuilderInterface
{
private InterceptorPipeline $pipeline;

Expand All @@ -38,11 +38,11 @@ public function withInterceptors(CoreInterceptorInterface|InterceptorInterface .
return $clone;
}

public function build(HandlerInterface|CoreInterface $last): InterceptorPipeline
public function build(HandlerInterface|CoreInterface $handler): InterceptorPipeline
{
/** @psalm-suppress InvalidArgument */
return $last instanceof HandlerInterface
? $this->pipeline->withHandler($last)
: $this->pipeline->withCore($last);
return $handler instanceof HandlerInterface
? $this->pipeline->withHandler($handler)
: $this->pipeline->withCore($handler);
}
}
2 changes: 1 addition & 1 deletion src/Hmvc/src/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Simple domain core to invoke controller actions.
*
* @deprecated use {@see \Spiral\Interceptors\Handler\ReflectionHandler} instead
* @deprecated use {@see \Spiral\Interceptors\Handler\AutowireHandler} instead
*/
final class Core extends AbstractCore
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
use Spiral\Interceptors\HandlerInterface;
use Spiral\Interceptors\Internal\ActionResolver;

class ReflectionHandler implements HandlerInterface
/**
* Handler resolves missing arguments from the container.
* It requires the Target to explicitly point to a method or function.
*/
final class AutowireHandler implements HandlerInterface
{
/**
* @param bool $resolveFromPath Try to resolve controller and action reflection from the target path if
* reflection is not provided.
*/
public function __construct(
/** @internal */
protected ContainerInterface $container,
protected bool $resolveFromPath = true,
) {
}

Expand All @@ -33,24 +32,11 @@ public function __construct(
public function handle(CallContextInterface $context): mixed
{
// Resolve controller method
$method = $context->getTarget()->getReflection();
$method = $context->getTarget()->getReflection() ?? throw new TargetCallException(
"Reflection not provided for target `{$context->getTarget()}`.",
TargetCallException::NOT_FOUND,
);
$path = $context->getTarget()->getPath();
if ($method === null) {
$this->resolveFromPath or throw new TargetCallException(
"Reflection not provided for target `{$context->getTarget()}`.",
TargetCallException::NOT_FOUND,
);

if (\count($path) !== 2) {
throw new TargetCallException(
"Invalid target path to resolve reflection for `{$context->getTarget()}`."
. ' Expected two parts: class and method.',
TargetCallException::NOT_FOUND,
);
}

$method = ActionResolver::pathToReflection(\reset($path), \next($path));
}

if ($method instanceof \ReflectionFunction) {
return $method->invokeArgs(
Expand Down
3 changes: 3 additions & 0 deletions src/Interceptors/src/HandlerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@

interface HandlerInterface
{
/**
* @throws \Throwable
*/
public function handle(CallContextInterface $context): mixed;
}
14 changes: 8 additions & 6 deletions src/Interceptors/src/PipelineBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@

namespace Spiral\Interceptors;

use Psr\EventDispatcher\EventDispatcherInterface;
use Spiral\Interceptors\Handler\InterceptorPipeline;

/**
* Accepts only {@see InterceptorInterface} instances to build a pipeline.
*/
class PipelineBuilder implements PipelineBuilderInterface
final class PipelineBuilder implements PipelineBuilderInterface
{
private InterceptorPipeline $pipeline;

public function __construct()
{
$this->pipeline = new InterceptorPipeline();
public function __construct(
?EventDispatcherInterface $dispatcher = null
) {
$this->pipeline = new InterceptorPipeline($dispatcher);
}

public function withInterceptors(InterceptorInterface ...$interceptors): static
Expand All @@ -25,8 +27,8 @@ public function withInterceptors(InterceptorInterface ...$interceptors): static
return $clone;
}

public function build(HandlerInterface $last): HandlerInterface
public function build(HandlerInterface $handler): HandlerInterface
{
return $this->pipeline->withHandler($last);
return $this->pipeline->withHandler($handler);
}
}
4 changes: 2 additions & 2 deletions src/Interceptors/src/PipelineBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface PipelineBuilderInterface
public function withInterceptors(InterceptorInterface ...$interceptors): static;

/**
* @param HandlerInterface $last The last handler in the pipeline.
* @param HandlerInterface $handler The last handler in the pipeline.
*/
public function build(HandlerInterface $last): HandlerInterface;
public function build(HandlerInterface $handler): HandlerInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
use Spiral\Interceptors\Context\CallContext;
use Spiral\Interceptors\Context\Target;
use Spiral\Interceptors\Exception\TargetCallException;
use Spiral\Interceptors\Handler\ReflectionHandler;
use Spiral\Interceptors\Handler\AutowireHandler;
use Spiral\Tests\Interceptors\Unit\Stub\TestService;

final class ReflectionHandlerTest extends TestCase
final class AutowireHandlerTest extends TestCase
{
public function testHandleReflectionMethodFromExtendedAbstractClass(): void
{
$c = new Container();
$handler = new ReflectionHandler($c, false);
$handler = new AutowireHandler($c);
// Call Context
$ctx = (new CallContext(Target::fromPair(TestService::class, 'parentMethod')))
->withArguments(['HELLO']);
Expand All @@ -38,7 +38,7 @@ public function testHandleReflectionFunction(): void
->method('get')
->with(ResolverInterface::class)
->willReturn($c);
$handler = new ReflectionHandler($container, false);
$handler = new AutowireHandler($container);
// Call Context
$ctx = new CallContext(Target::fromReflectionFunction(new \ReflectionFunction('strtoupper')));
$ctx = $ctx->withArguments(['hello']);
Expand All @@ -57,7 +57,7 @@ public function testHandleReflectionMethodWithObject(): void
->method('get')
->with(ResolverInterface::class)
->willReturn($c);
$handler = new ReflectionHandler($container, false);
$handler = new AutowireHandler($container);
// Call Context
$service = new TestService();
$ctx = (new CallContext(Target::fromPair($service, 'parentMethod')))
Expand All @@ -68,48 +68,28 @@ public function testHandleReflectionMethodWithObject(): void
self::assertSame('hello', $result);
}

public function testWithoutResolvingFromPathAndReflection(): void
public function testWithoutResolvingFromPath(): void
{
$container = self::createMock(ContainerInterface::class);

$handler = new ReflectionHandler($container, false);
$handler = new AutowireHandler($container);

self::expectException(TargetCallException::class);
self::expectExceptionMessageMatches('/Reflection not provided for target/');
self::expectExceptionMessage('Reflection not provided for target');

$handler->handle(new CallContext(Target::fromPathString('foo')));
}

public function testWithoutReflectionWithResolvingFromPathWithIncorrectPath(): void
public function testWithoutReflectionWithCallableArray(): void
{
$handler = $this->createHandler();

self::expectException(TargetCallException::class);
self::expectExceptionMessageMatches('/Invalid target path to resolve reflection/');

$handler->handle(new CallContext(Target::fromPathArray(['foo', 'bar', 'baz'])));
}

public function testWithoutReflectionWithResolvingFromPathWithWrongPath(): void
{
$handler = $this->createHandler();

self::expectException(TargetCallException::class);
self::expectExceptionMessageMatches('/Invalid action/');

$handler->handle(new CallContext(Target::fromPathArray([TestService::class, 'nonExistingMethod'])));
}

public function testWithoutReflectionWithResolvingFromPath(): void
{
$handler = $this->createHandler([
TestService::class => $service = new TestService(),
]);

self::assertSame(0, $service->counter);
self::expectExceptionMessage(
\sprintf('Reflection not provided for target `%s.increment`.', TestService::class),
);

$handler->handle(new CallContext(Target::fromPathArray([TestService::class, 'increment'])));
self::assertSame(1, $service->counter);
}

public function testUsingResolver(): void
Expand All @@ -125,16 +105,15 @@ public function testUsingResolver(): void
self::assertSame('HELLO', $result);
}

public function createHandler(array $definitions = [], bool $resolveFromPath = true): ReflectionHandler
public function createHandler(array $definitions = []): AutowireHandler
{
$container = new Container();
foreach ($definitions as $id => $definition) {
$container->bind($id, $definition);
}

return new ReflectionHandler(
return new AutowireHandler(
$container,
$resolveFromPath,
);
}
}
Loading