Kontynuujemy pracę nad routerem. Poznajemy pojęcie middleware i staramy się je w prosty sposób zaimplementować. Do dzieła.
Na początku przypomnienie, co już mamy:
<?php
class TransactionController {
public function makeTransaction($params){
echo "Making transaction {$params['transaction']} <br>";
echo "Recepit: {$params['receipt']} <br>";
echo "DONE";
}
}
class Router {
private array $routes = [];
public function normalizePath($path){
$path = trim($path, '/');
$path = "/{$path}/";
$path = preg_replace('#[/]{2,}#', '/', $path);
return $path;
}
public function add(string $method, string $path, array $controller)
{
$path = $this->normalizePath($path);
$regexPath = preg_replace('#{[^/]+}#', '([^/]+)', $path);
$this->routes[] = [
'path' => $path,
'method' => strtoupper($method),
'controller' => $controller,
'middlewares' => [],
'regexPath' => $regexPath
];
}
public function dispatch(string $path, string $method, $container = null)
{
$path = $this->normalizePath($path);
$method = strtoupper($_POST['_METHOD'] ?? $method);
foreach ($this->routes as $route) {
if (
!preg_match("#^{$route['regexPath']}$#", $path, $paramValues) ||
$route['method'] !== $method
) {
continue;
}
array_shift($paramValues);
preg_match_all('#{([^/]+)}#', $route['path'], $paramKeys);
$paramKeys = $paramKeys[1];
$params = array_combine($paramKeys, $paramValues);
[$class, $function] = $route['controller'];
$controllerInstance = $container ?
$container->resolve($class) :
new $class;
$action = fn () => $controllerInstance->{$function}($params);
$action();
return;
}
}
}
$router = new Router;
$router->add('GET', '/transaction/{transaction}/receipt/{receipt}/', [TransactionController::class, 'makeTransaction']);
$router->dispatch('/transaction/123/receipt/helloworld/', 'GET');
// Making transaction 123
// Recepit: helloworld
// DONE
Middleware to takie coś, co wykonuje swoją robotę i przechodzi do następnego kroku. Ostatnim krokiem jest dispatch na wybrany route.
Dokonamy sobie zatem drobnej zmiany i napiszemy interfejs dla Middleware:
$router = new Router;
$router->add('GET', '/transaction/{transaction}/receipt/{receipt}/', [TransactionController::class, 'makeTransaction']);
$next = fn() => $router->dispatch('/transaction/123/receipt/helloworld/', 'GET');
interface MiddlewareInterface
{
public function process(callable $next);
}
Teraz piszemy głupie middleware:
class StupidMiddleware implements MiddlewareInterface
{
public function process(callable $next)
{
echo "This is stupid middleware speaking <br>";
$next();
}
}
Ok, testujemy:
class TransactionController {
//(...)
}
class Router {
//(...)
}
$router = new Router;
$router->add('GET', '/transaction/{transaction}/receipt/{receipt}/', [TransactionController::class, 'makeTransaction']);
$next = fn() => $router->dispatch('/transaction/123/receipt/helloworld/', 'GET');
interface MiddlewareInterface
{
public function process(callable $next);
}
class StupidMiddleware implements MiddlewareInterface
{
public function process(callable $next)
{
echo "This is stupid middleware speaking <br>";
$next();
}
}
$stupidMiddleware = new StupidMiddleware;
$stupidMiddleware->process($next);
// This is stupid middleware speaking
// Making transaction 123
// Recepit: helloworld
// DONE
Wykonało się i przeszło do następnej akcji. W następnej lekcji implementujemy łańcuch middleware w routerze.