phoole/route

View on GitHub
src/Router.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

/**
 * Phoole (PHP7.2+)
 *
 * @category  Library
 * @package   Phoole\Route
 * @copyright Copyright (c) 2019 Hong Zhang
 */
declare(strict_types=1);

namespace Phoole\Route;

use Phoole\Route\Util\Result;
use Phoole\Route\Util\RouteAwareTrait;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Phoole\Route\Parser\ParserInterface;
use Phoole\Route\Parser\FastRouteParser;
use Phoole\Route\Resolver\DefaultResolver;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Phoole\Route\Resolver\ResolverInterface;

/**
 * Router
 *
 * @package Phoole\Route
 */
class Router implements MiddlewareInterface
{
    use RouteAwareTrait;
    /**
     * context name used for storing parsed parameters
     */
    const URI_PARAMETERS = '__parsedParams__';

    /**
     * controller/action name resolver
     *
     * @var ResolverInterface
     */
    protected $resolver;

    /**
     * Load route definitions and set the parser
     *
     * @param  array             $routes    route definitions
     * @param  ResolverInterface $resolver  controller/action name resolver
     * @param  ParserInterface   $parser    routes parser/matcher
     */
    public function __construct(
        array $routes = [],
        ?ResolverInterface $resolver = NULL,
        ?ParserInterface $parser = NULL
    ) {
        $this
            ->loadRoutes($routes)
            ->setResolver($resolver ?? new DefaultResolver())
            ->setParser($parser ?? new FastRouteParser());
    }

    /**
     * Middleware compliant
     *
     * {@inheritDoc}
     */
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $result = $this->match($request);
        if ($result->isMatched()) {
            return $this->handleResult($result);
        } else {
            return $handler->handle($request);
        }
    }

    /**
     * Match request with predefined routes, returns a Result object
     *
     * @param  ServerRequestInterface $request
     * @return Result
     */
    public function match(ServerRequestInterface $request): Result
    {
        $result = new Result($request);
        return $this->routeMatch($result);
    }

    /**
     * Utility function for getting parameter values stored in the request
     *
     * @param  ServerRequestInterface $request
     * @return array
     */
    public static function getParams(ServerRequestInterface $request): array
    {
        $params = $request->getAttribute(Router::URI_PARAMETERS) ?? [];
        return $params;
    }

    /**
     * @param  ResolverInterface $resolver
     * @return $this
     */
    protected function setResolver(ResolverInterface $resolver)
    {
        $this->resolver = $resolver;
        return $this;
    }

    /**
     * @param  Result $result
     * @return ResponseInterface
     * @throws \InvalidArgumentException    if resolver failure
     */
    protected function handleResult(Result $result): ResponseInterface
    {
        $request = $result->getRequest();
        $handler = $result->getHandler();
        if (is_callable($handler)) {
            return $handler($request);
        } elseif ($handler instanceof RequestHandlerInterface) {
            return $handler->handle($request);
        } else {
            $handler = $this->resolver->resolve($handler, self::getParams($request));
            return $handler($request);
        }
    }
}