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

New PathMiddlewareDecorator #183

Open
2 tasks done
mnavarrocarter opened this issue Jan 3, 2019 · 2 comments
Open
2 tasks done

New PathMiddlewareDecorator #183

mnavarrocarter opened this issue Jan 3, 2019 · 2 comments

Comments

@mnavarrocarter
Copy link

mnavarrocarter commented Jan 3, 2019

  • 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?

@weierophinney
Copy link
Member

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

  • The above class.
  • Unit tests demonstrating the various ways it can be used.
  • Documentation
  • Potentially a helper function similar to the path() utility function for simplifying decorating middleware/handlers with this.

Submit the PR against the develop branch.

Thanks!

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas/laminas-stratigility; a new issue has been opened at laminas/laminas-stratigility#6.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants