Overview

Namespaces

  • Routing
  • Teto
    • Overview
    • Namespace
    • Class
      1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 
    <?php
    
    namespace Teto\Routing;
    
    /**
     * Router
     *
     * @author    USAMI Kenta <tadsan@zonu.me>
     * @copyright 2016 BaguetteHQ
     * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0
     */
    class Router
    {
        const _ext = '?ext';
        const _sep = "\x1E";
    
        /** @var \Teto\Routing\Action[] */
        public $variable_actions = [];
    
        /** @var \Teto\Routing\Action[] */
        public $fixed_actions = [];
    
        /** @var \Teto\Routing\Action[] */
        public $named_actions = [];
    
        /** @var array */
        public $error_action = [];
    
        public function __set($name, $value)
        {
            throw new \OutOfRangeException("Unexpected key:'$name'");
        }
    
        /**
         * @param  array  $route_map
         * @param  string $method
         * @param  string $path
         * @return \Teto\Routing\Action
         */
        public static function dispatch(array $route_map, $method, $path)
        {
            return (new Router($route_map))->match($method, $path);
        }
    
        /**
         * @param array $route_map
         */
        public function __construct(array $route_map)
        {
            foreach ($route_map as $k => $m) {
                ($k !== '#404')
                    ? $this->setAction($k, $m)
                    : $this->setSpecialAction($k, $m);
            }
        }
    
        /**
         * @param   string $method
         * @param   string $path
         * @return  \Teto\Routing\Action
         */
        public function match($method, $path)
        {
            if ($method === 'HEAD') { $method = 'GET'; }
            if (strpos($path, '//') !== false || strpos($path, self::_sep) !== false) {
                return $this->getNotFoundAction($method, $path);
            }
    
            $split_path = array_values(array_filter(explode('/', $path), 'strlen'));
            $count = count($split_path);
    
            $ext  = '';
    
            if ($count > 0) {
                $file = explode('.', $split_path[$count - 1], 2);
                if (isset($file[1]) && strlen($file[1]) > 0) {
                    if (strlen($file[1]) > 0) {
                        list($split_path[$count - 1], $ext) = $file;
                    } else {
                        $split_path[$count - 1] .= '.';
                    }
                }
            }
    
            $fixed_key = implode(self::_sep, $split_path);
            if (isset($this->fixed_actions[$fixed_key])) {
                $action = $this->fixed_actions[$fixed_key];
                if ($matched = $action->match($method, $split_path, $ext)) {
                    return $matched;
                }
            }
    
            if (isset($this->variable_actions[$count])) {
                foreach ($this->variable_actions[$count] as $action) {
                    if ($matched = $action->match($method, $split_path, $ext)) {
                        return $matched;
                    }
                }
            }
    
            return $this->getNotFoundAction($method, $path, $ext);
        }
    
        /**
         * @param   string $method
         * @param   string $path
         * @return  \Teto\Routing\Action
         */
        public function getNotFoundAction($method, $path)
        {
            $split_path = array_values(array_filter(explode('/', $path), 'strlen'));
    
            return new NotFoundAction(
                [$method],
                $split_path,
                [],
                [],
                $this->error_action['#404']
            );
        }
    
        /**
         * @param int|string $key
         * @param array      $action_tuple
         */
        public function setAction($key, array $action_tuple)
        {
            if (isset($action_tuple[self::_ext])) {
                $ext = $action_tuple[self::_ext];
                unset($action_tuple[self::_ext]);
            } else {
                $ext = [];
            }
    
            $method = array_shift($action_tuple);
            $path   = array_shift($action_tuple);
            $value  = array_shift($action_tuple) ?: true ;
            $params = array_shift($action_tuple) ?: [] ;
            $action = Action::create($method, $path, $value, $ext, $params);
    
            if ($action->param_pos) {
                $count  = count($action->split_path);
                if (!isset($this->variable_actions[$count])) {
                    $this->variable_actions[$count] = [];
                }
                $this->variable_actions[$count][] = $action;
            } else {
                $fixed_key = implode(self::_sep, $action->split_path);
                $this->fixed_actions[$fixed_key] = $action;
            }
    
            if (!is_numeric($key)) {
                $this->named_actions[$key] = $action;
            }
        }
    
        /**
         * @param string $name
         * @param mixed  $value
         */
        public function setSpecialAction($name, $value)
        {
            $this->error_action[$name] = $value;
        }
    
        /**
         * @param string  $name
         * @param array   $param
         * @param boolean $strict
         */
        public function makePath($name, array $param = [], $strict = false)
        {
            if (empty($this->named_actions[$name])) {
                throw new \OutOfRangeException("\"$name\" is not exists.");
            }
    
            if (isset($param[self::_ext])) {
                $ext = $param[self::_ext];
                unset($param[self::_ext]);
            } else {
                $ext = null;
            }
    
            return $this->named_actions[$name]->makePath($param, $ext, $strict);
        }
    }
    
    Teto Routing API documentation generated by ApiGen