Resource Router – filtering routes by http method

4 years ago

livioribeiro
Member | 7
+
0
-

After some time without working with Nette, I decided to take a look at the project I was working on and started playing with some SPA frameworks. Then, feeling the need to filter routes by http method, I extended the Nette Route class:

<?php

namespace App\Router;

use Nette\Application\Routers\Route;
use Nette\Application\Routers\RouteList;
use Nette\Utils\Strings;

class ResourceRoute extends Route {

    /** @var array */
    private $methods;

    /**
     *
     * @param string|array $method
     * @param type $mask
     * @param type $metadata
     * @param type $flags
     */
    public function __construct($method, $mask, $metadata = array(), $flags = 0) {
        parent::__construct($mask, $metadata, $flags);

        if ($method === NULL) {
            $this->methods = NULL;
        } else if (!is_array($method)) {
            $this->methods = [Strings::upper($method)];
        } else {
            $this->methods = array_map(Strings::upper, $method);
        }
    }

    public function match(\Nette\Http\IRequest $httpRequest) {
        /*
         * If $this->methods is not NULL, check the request method
         */
        if ($this->methods !== NULL) {
            $method = Strings::upper($httpRequest->getMethod());
            $methodFromHeader = $httpRequest->getHeader('X-Method-Override', NULL);
            $methodFromPost = $httpRequest->getPost('__method', NULL);

            /*
             * If method is GET, do not look for overrides
             */
            if ($method === 'GET' && FALSE === array_search($method, $this->methods)) {
                return NULL;
            }

            /*
             * If method is not GET, look first at the request method, then at the
             * header override and finnaly at the post parameter override
             */
            if (FALSE === array_search($method, $this->methods)
                    && FALSE === array_search($methodFromHeader, $this->methods)
                    && FALSE === array_search($methodFromPost, $this->methods)) {

                return NULL;
            }
        }

        return parent::match($httpRequest);
    }

    public static function get($mask, $metadata = array(), $flags = 0) {
        return new static('GET', $mask, $metadata, $flags);
    }

    public static function post($mask, $metadata = array(), $flags = 0) {
        return new static('POST', $mask, $metadata, $flags);
    }

    public static function put($mask, $metadata = array(), $flags = 0) {
        return new static('PUT', $mask, $metadata, $flags);
    }

    public static function delete($mask, $metadata = array(), $flags = 0) {
        return new static('DELETE', $mask, $metadata, $flags);
    }

    public static function patch($mask, $metadata = array(), $flags = 0) {
        return new static('PATCH', $mask, $metadata, $flags);
    }

    public static function resource($baseMask, $controllerName) {
        $base = rtrim($baseMask, '/');
        $routeList = new RouteList();

        $routeList[] = static::get($base, "$controllerName:readAll");
        $routeList[] = static::post($base, "$controllerName:create");
        $routeList[] = static::get("$base/<id>", "$controllerName:read");
        $routeList[] = static::put("$base/<id>", "$controllerName:update");
        $routeList[] = static::delete("$base/<id>", "$controllerName:delete");

        return $routeList;
    }

}
?>

I just tested it to see if it works, so the implementation may contain bugs.

So, what do you think about it? Is it good? Is it flawed? I'll appreciate any feedback.