Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

New PathMiddlewareDecorator #183

Open
@mnavarrocarter

Description

@mnavarrocarter
  • I was not able to find an open or closed issue matching what I'm seeing.
  • This is not a question.

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

  • I needed it to match a routes flexibly using regular expressions if necessary.
  • I needed it to match optionally by request route
  • I needed to decide if the middleware being decorated was going to execute if the routed matched or didn't match.

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 <[email protected]>
 */
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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions