Strident/Router

View on GitHub
src/RouteMatcher.php

Summary

Maintainability
A
45 mins
Test Coverage
<?php

/**
 * This file is part of the Router package.
 *
 * @package Router
 * @since   2015
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Strident\Router;

/**
 * RouteMatcher
 *
 * @author Elliot Wright
 */
class RouteMatcher implements RouteMatcherInterface
{
    /**
     * {@inheritDoc}
     */
    public function match($method, $url, $routes)
    {
        $parsed = parse_url($url);
        $path = $parsed['path'];

        $matched = null;
        /* @var Route[] $routes */
        foreach ($routes as $route) {
            $compiled = $this->compileRoute($route);

            if (!preg_match($compiled['regexp'], $path, $variables)) {
                continue;
            }

            if (!$route->hasTargetForMethod($method)) {
                continue;
            }

            array_shift($variables);

            $matched = [
                'method'     => $method,
                'name'       => $route->getName(),
                'parameters' => $variables,
                'target'     => $route->getTargetForMethod($method),
            ];

            break;
        }

        return $matched;
    }

    /**
     * {@inheritDoc}
     *
     * @throws RuntimeException
     */
    protected function compileRoute(Route $route)
    {
        $parameters = $this->processPathParameters($route->getPath());
        $regexp = $route->getPath();

        foreach ($parameters as $parameter) {
            if (substr_count($route->getPath(), '{'.$parameter.'}') > 1) {
                throw new \RuntimeException(sprintf(
                    'Route name "%s" cannot reference variable "%s" more than once.',
                    $route->getName(),
                    $parameter
                ));
            }

            $regexp = str_replace(
                '{' . $parameter . '}',
                '(?<' . $parameter . '>[A-z0-9_-]+)',
                $regexp
            );
        }

        $regexp = "#^$regexp$#";

        return [
            'parameters' => $parameters,
            'regexp' => $regexp,
        ];
    }

    /**
     * Get tokens for given route path
     *
     * @param string $path
     *
     * @return array
     */
    protected function processPathParameters($path)
    {
        preg_match_all('#{(\w+)}#', $path, $matches);

        return $matches[1];
    }
}