Skip to content

Commit

Permalink
Merge pull request #1128: Polish interceptors
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk authored Sep 3, 2024
2 parents 569ade3 + 8feba72 commit 6b5f694
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 72 deletions.
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,
);
}
}

0 comments on commit 6b5f694

Please sign in to comment.