atelierspierrot/mvc-fundamental

View on GitHub
src/MVCFundamental/Basic/Router.php

Summary

Maintainability
B
5 hrs
Test Coverage
<?php
/**
 * This file is part of the MVC-Fundamental package.
 *
 * Copyright (c) 2013-2016 Pierre Cassat <me@e-piwi.fr> and contributors
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The source code of this package is available online at
 * <http://github.com/atelierspierrot/mvc-fundamental>.
 */

namespace MVCFundamental\Basic;

use \MVCFundamental\Exception\AccessForbiddenException;
use \MVCFundamental\Interfaces\RouterInterface;
use \MVCFundamental\Interfaces\RouteInterface;
use \Patterns\Commons\Collection;

/**
 * Class Router
 */
class Router
    implements RouterInterface
{

    /**
     * @var \Patterns\Commons\Collection
     */
    protected $_collection;

    /**
     *
     */
    public function __construct()
    {
        $this->_collection = new Collection();
    }

    /**
     * @param string $uri
     * @param array $arguments
     * @param string $method
     * @return array ( callback , parameters )
     * @throws AccessForbiddenException
     */
    public function distribute($uri, array $arguments = array(), $method = 'get')
    {
        // strip double slashes
        $uri        = str_replace('//', '/', $uri);

        // strip query arguments
        if (false!==($pos = strpos($uri, '?'))) {
            $uri = substr($uri, 0, $pos);
        }

        // routes matching
        foreach ($this->_collection as $route) {
            if (false!==preg_match('~^'.$route->getMatch().'$~', $uri, $uri_matches) && count($uri_matches)>0) {
                $callback = $route->getCallback();
                foreach ($uri_matches as $var=>$val) {
                    if (is_string($var)) {
                        $arguments[$var] = $val;
                    }
                }
                if ($route->getMethod()!=='get' && $route->getMethod()!==strtolower($method)) {
                    throw new AccessForbiddenException('Wrong data type!');
                }
                return array($callback, $arguments);
            }
        }

        // automatic routing if uri is not empty
        if (strlen($uri)>1) {

            // case controller/method
            if (strpos($uri, '/', 1)!==false) {
                $parts = explode('/', substr($uri, 1));
                $callback = array($parts[0], $parts[1]);
                array_shift($parts);
                array_shift($parts);
                $index      = null;
                foreach ($parts as $item) {
                    if (is_null($index)) {
                        $index = $item;
                    } else {
                        $arguments[$index] = $item;
                        $index = null;
                    }
                }
                return array($callback, $arguments);

            // case method only
            } else {
                return array(substr($uri, 1), $arguments);
            }
        }

        return null;
    }

    /**
     * @param array $routes
     */
    public function setRoutes(array $routes)
    {
        foreach ($routes as $route) {
            $this->addRoute($route);
        }
    }

    /**
     * @param \MVCFundamental\Interfaces\RouteInterface $route
     * @return $this
     */
    public function addRoute(RouteInterface $route)
    {
        $this->_collection[] = $route;
        return $this;
    }
}