zendframework / zend-stratigility

Middleware for PHP built on top of PSR-7 and PSR-15
BSD 3-Clause "New" or "Revised" License
235 stars 57 forks source link

New PathMiddlewareDecorator #183

Open mnavarrocarter opened 5 years ago

mnavarrocarter commented 5 years ago

I was taking a look to the PathMiddlewareDecorator for a project I'm working on, but it kinda didn't suited my needs.

So I ended up building my own decorator. How keen are you guys of accepting a PR with it? Here's a very naive implementation:


use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as NextHandler;

/**
 * Decorates a middleware to be executed on a router pattern match/un-match
 *
 * You can optionally pass a method to the arguments.
 *
 * @author Matías Navarro Carter <mnavarrocarter@gmail.com>
 */
final class PathMiddlewareDecorator implements MiddlewareInterface
{
    public const IF_MATCHES = 1;
    public const IF_NOT_MATCHES = 0;

    /**
     * @var MiddlewareInterface
     */
    private $middleware;
    /**
     * @var int
     */
    private $executionRule;
    /**
     * @var string|string[]
     */
    private $path;
    /**
     * @var string|null
     */
    private $method;

    /**
     * PathMiddlewareDecorator constructor.
     *
     * @param MiddlewareInterface $middleware The middleware to execute.
     * @param string|string[]     $path A path pattern or an array of patterns.
     * @param string|null         $method A method to match.
     * @param int                 $executionRule The rule of execution.
     */
    public function __construct(
        MiddlewareInterface $middleware,
        $path,
        string $method = null,
        int $executionRule = self::IF_MATCHES
    ) {
        $this->middleware = $middleware;
        $this->path = $path;
        $this->method = $method;
        $this->executionRule = $executionRule;
    }

    /**
     * @param Request     $request
     * @param NextHandler $handler
     *
     * @return Response
     */
    public function process(Request $request, NextHandler $handler): Response
    {
        $match = $this->matches($request);

        if (self::IF_MATCHES === $this->executionRule && true === $match) {
            return $this->middleware->process($request, $handler);
        }
        if (self::IF_NOT_MATCHES === $this->executionRule && false === $match) {
            return $this->middleware->process($request, $handler);
        }

        return $handler->handle($request);
    }

    /**
     * @param Request $request
     *
     * @return bool
     */
    private function matches(Request $request): bool
    {
        if ($this->method && $request->getMethod() !== $this->method) {
            return false;
        }

        return $this->matchesRegex($request->getUri()->getPath(), $this->path);
    }

    /**
     * @param string $requestPath
     * @param        $pathOrPaths
     *
     * @return bool
     */
    private function matchesRegex(string $requestPath, $pathOrPaths): bool
    {
        if (is_array($pathOrPaths)) {
            foreach ($pathOrPaths as $string) {
                $result = $this->matchesRegex($requestPath, $string);
                if (true === $result) {
                    return true;
                }
            }
        }
        if (\is_string($pathOrPaths)) {
            return 0 !== preg_match('/'.str_replace('/', '\/', $pathOrPaths).'/', $requestPath);
        }

        return false;
    }
}

Of course it should be named differently to the one you guys already have. Maybe ConfigurablePathMiddlewareDecorator?

weierophinney commented 5 years ago

This is definitely interesting. What we'd need from you is a pull request with:

Submit the PR against the develop branch.

Thanks!

weierophinney commented 4 years ago

This repository has been closed and moved to laminas/laminas-stratigility; a new issue has been opened at https://github.com/laminas/laminas-stratigility/issues/6.