Using Expressive’s middleware in Penny Framework
If we are using Penny Framework, we can use Expressive‘s middleware. We can do that with passing callable $next that handle request and response with Penny Event. The $next is simply like the following:
$next = function($request, $response) use ($event) {
$event->setRequest($request);
$event->setResponse($response);
};
and we are ready to go! Let’s try to do real example. We need to use los/basepath that can apply “base path” in our application that point to classic-app/public and we can to call: /classic-app/public after our host.
$ composer require los/basepath
We need to invoke the middleware to make it called. So, if we do in ‘bootstrap’ event, we can do:
$eventManager->attach('bootstrap', function($event) {
$next = function($request, $response) use ($event) {
$event->setRequest($request);
$event->setResponse($response);
};
$basepathMiddleware = new \LosMiddleware\BasePath\BasePath(
'/classic-app/public'
);
$basepathMiddleware(
$event->getRequest(),
$event->getResponse(),
$next
);
});
This is the case if we are using penny skeleton app and we install under ‘classic-app’ directory, and the “front controller” is in public/index.php.
For routed middleware, we can just do the register the middleware as controller:
// config/di.php
// ...
'router' => function () {
return \FastRoute\simpleDispatcher(function (\FastRoute\RouteCollector $r) {
$r->addRoute(
'GET',
'/',
['App\Controller\IndexController', 'index']
);
$r->addRoute(
'GET',
'/api/ping',
['App\Controller\PingAction', '__invoke']
);
});
},
// ...
That’s it 😉
Middleware implementation in Penny Framework
Penny is a microframework that has different idea for accomplishing middleware implementation. If we found other frameworks that implements this signatures:
function ($request, $response, $next = null);
In Penny Framework, Middleware implemented via listener that has priority that we call before or/and after. If we need to initialize application flow, you may use ‘bootstrap’ event:
// config/di.php
use App\Middleware\BootstrapMiddleware;
use function DI\decorate;
return [
'event_manager' => decorate(function($eventManager, $container) {
$eventManager->attach(
'bootstrap',
[$container->get(BootstrapMiddleware::class), 'bootstrap']
);
// other attach here...
return $eventManager;
}),
// other service definitions here...
];
We want the middleware executed in all application flow in all controller in the end? use ‘*’ and negative priority:
// config/di.php
use App\Middleware\AllEnderMiddleware;
use function DI\decorate;
return [
'event_manager' => decorate(function($eventManager, $container) {
$eventManager->attach(
'*',
[$container->get(AllEnderMiddleware::class), 'end'],
-1
);
// other attach here...
return $eventManager;
}),
// other service definitions here...
];
Wanna handle for specific controller’s action ? Use following usage:
// config/di.php
use App\Controller\IndexController;
use App\Middleware\IndexMiddleware;
use function DI\decorate;
return [
'event_manager' => decorate(function($eventManager, $container) {
// before ...
$eventManager->attach(
IndexController::class.'.index',
[$container->get(IndexMiddleware::class), 'pre'],
1
);
// after ...
$eventManager->attach(
IndexController::class.'.index',
[$container->get(IndexMiddleware::class), 'post'],
-1
);
// other attach here...
return $eventManager;
}),
// other service definitions here...
];
If we use default Penny EventManager implementation, which is usage Zend Framework 2 EventManager, higher priority will be served first, lower priority will be served later.
If you are familiar with CakePHP, there is already a CakePHP Event implementation, that will serve lower priority first, higher later.
For callable listener, we may create listener service like the following:
namespace App\Middleware;
class IndexMiddleware
{
public function pre($event)
{
$request = $event->getRequest();
$response = $event->getResponse();
// manipulate request or/and response here
$request = $request->withAttribute('foo', 'fooValue');
// apply manipulated request or/and response
$event->setRequest($request);
$event->setResponse($response);
}
public function post($event)
{
$request = $event->getRequest();
$response = $event->getResponse();
// manipulate request or/and response here
$response = $response->withHeader('X-Powered-By', 'JAVA');
// apply manipulated request or/and response
$event->setRequest($request);
$event->setResponse($response);
}
}
We can then register the middleware in our Service Container:
//config/di.php
use App\Middleware\AllEnderMiddleware;
use App\Middleware\BootstrapMiddleware;
use App\Middleware\IndexMiddleware;
use function DI\object;
return [
// ...
AllEnderMiddleware::class => object(AllEnderMiddleware::class),
BootstrapMiddleware::class => object(BootstrapMiddleware::class),
IndexMiddleware::class => object(IndexMiddleware::class),
];
leave a comment