ellipse / handlers-controller
Psr-15 request handler proxying a class method using a Psr-11 container entry
Requires
- php: >=7.0
- ellipse/container-overridden: ^1.0
- ellipse/resolvable-callable: ^1.0
- ellipse/type-errors: ^1.0
- psr/container: ^1.0
- psr/http-message: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
Requires (Dev)
- eloquent/phony-kahlan: ^1.0
- kahlan/kahlan: ^4.0
This package is auto-updated.
Last update: 2024-10-26 01:12:44 UTC
README
This package provides a Psr-15 request handler proxying a class method using a Psr-11 container.
Require php >= 7.0
Installation composer require ellipse/handlers-controller
Run tests ./vendor/bin/kahlan
Using controllers as request handlers
The class Ellipse\Handlers\ControllerRequestHandler
takes an implementation of Psr\Container\ContainerInterface
, a container id, a method name and an optional array of request attribute names as parameters. Its ->handle()
method retrieve an instance of the controller class from the container and call its method with the given name in order to return a response.
The controller method is executed by using the container to retrieve values for its type hinted parameters. Request attribute values matching the given request attribute names are used for the non-type hinted parameters, in the order they are listed.
Also when the controller method has a parameter type hinted as Psr\Http\Message\ServerRequestInterface
, the actual Psr-7 request received by the request handler is used. It means when a middleware create a new request (since Psr-7 requests are immutable) the controller method receive this new request.
An Ellipse\Handlers\Exceptions\ContainedControllerTypeException
is thrown when the controller retrieved from the container is not an object.
<?php namespace App\Controllers; use Psr\Http\Message\ServerRequestInterface; use App\SomeService; use App\SomeOtherService; class SomeController { public function __construct(SomeService $service) { // } public function index(SomeOtherService $service) { // return a Psr-7 response } public function show(SomeOtherService $service, $some_id) { // return a Psr-7 response } public function store(ServerRequestInterface $request) { // return a Psr-7 response } }
<?php namespace App; use SomePsr11Container; use Ellipse\Handlers\ControllerRequestHandler; use App\Controllers\SomeController; // Get some Psr-11 container. $container = new SomePsr11Container; // Register the controller in the container. $container->set(SomeController::class, function ($container) { return new SomeController(new SomeService); }); // Register some services in the container. $container->set(SomeOtherService::class, function ($container) { return new SomeOtherService; }); // Those request handlers are using the Psr-11 container, controller class names, methods and attributes. $handler1 = new ControllerRequestHandler($container, SomeController::class, 'index'); $handler2 = new ControllerRequestHandler($container, SomeController::class, 'show', ['some_id']); $handler3 = new ControllerRequestHandler($container, SomeController::class, 'store'); // The request handler ->handle() method proxy SomeController index method. // The contained instance of SomeOtherService is passed to the method. $response = $handler1->handle($request); // Here the request handler ->handle() method proxy SomeController show method. // The contained instance of SomeOtherService is passed to the method. // The $some_id parameter will receive the request 'some_id' attribute value. $response = $handler2->handle($request); // Here the request handler ->handle() method proxy SomeController store method. // The $request parameter will receive the actual Psr-7 request received by the request handler. $response = $handler3->handle($request);
Example using auto wiring
It can be cumbersome to register every controller classes in the container. Here is how to auto wire controller instances using the Ellipse\Container\ReflectionContainer
class from the ellipse/container-reflection package.
<?php // Let controller classes implement some dummy interface specific to the application. namespace App\Controllers; class SomeController implements ControllerInterface { // ... }
<?php namespace App; use SomePsr11Container; use Ellipse\Container\ReflectionContainer; use Ellipse\Handlers\ControllerRequestHandler; use App\Controllers\ControllerInterface; use App\Controllers\SomeController; // Get some Psr-11 container. $container = new SomePsr11Container; // Decorate the container with a reflection container. // Specify the classes implementing ControllerInterface can be auto wired. $reflection = new ReflectionContainer($container, [ ControllerInterface::class, ]); // Create a controller request handler using the reflection container and a controller class name. $handler = new ControllerRequestHandler($reflection, SomeController::class, 'index'); // An instance of SomeController is built using auto wiring. $response = $handler->handle($request);