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: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 
    <?php
    namespace Teto\Routing;
    
    /**
     * Action object
     *
     * @author    USAMI Kenta <tadsan@zonu.me>
     * @copyright 2016 BaguetteHQ
     * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0
     *
     * @property-read string[] $methods
     * @property-read string[] $split_path
     * @property-read array    $param_pos
     * @property-read mixed    $value
     * @property-read string   $extension
     * @property-read boolean  $is_wildcard
     * @property-read string[] $available_extensions
     */
    class Action
    {
        use \Teto\Object\TypeAssert;
        const WILDCARD = '*';
    
        /** @var string[] */
        public $methods;
        /** @var string[] */
        public $split_path;
        /** @var array */
        public $param_pos;
        /** @var mixed */
        public $value;
        /** @var string */
        public $extension;
        /** @var string */
        public $is_wildcard;
        /** @var array */
        public $available_extensions;
    
        private static $enum_values = [
            'methods' => ['GET', 'POST'],
        ];
    
        /**
         * @param string[] $methods
         * @param string[] $split_path
         * @param array    $param_pos
         * @param string[] $extension
         * @param mixed    $value
         */
        public function __construct(array $methods, array $split_path, array $param_pos, array $available_extensions, $value)
        {
            static::assertMethods($methods);
    
            $this->methods     = $methods;
            $this->split_path  = $split_path;
            $this->param_pos   = $param_pos;
            $this->value       = $value;
            $this->param       = [];
            $this->is_wildcard = in_array(self::WILDCARD, $available_extensions, true);
            $this->available_extensions
                = empty($available_extensions) ? ['' => true]
                : array_fill_keys($available_extensions, true) ;
        }
    
        /**
         * @param  string   $request_method
         * @param  string[] $request_path
         * @param  string   $extension
         * @return Action|false
         */
        public function match($request_method, array $request_path, $extension)
        {
            $request_len = count($request_path);
    
            if (!in_array($request_method, $this->methods, true) ||
                $request_len !== count($this->split_path)) {
                return false;
            }
    
            if ($this->available_extensions === ['' => true]) {
                if (strlen($extension) > 0) {
                    $request_path[$request_len - 1] .= '.' . $extension;
                }
                $extension = '';
            }
    
            if ($this->matchExtension($extension)) {
                $this->extension = $extension;
            } else {
                return false;
            }
    
            if (empty($this->param_pos) && ($request_path === $this->split_path)) {
                return $this;
            }
    
            foreach ($this->split_path as $i => $p) {
                $q = $request_path[$i];
    
                if (isset($this->param_pos[$i])) {
                    if (!preg_match($p, $q, $matches)) {
                        $this->param = [];
                        return false;
                    }
    
                    $k = $this->param_pos[$i];
                    $param_tmp = $this->param;
                    $param_tmp[$k] = isset($matches[1]) ? $matches[1] : $matches[0];
                    $this->param = $param_tmp;
                } elseif ($q !== $p) {
                    $this->param = [];
                    return false;
                }
            }
    
            return $this;
        }
    
        /**
         * @param  string  $extension
         * @return boolean
         */
        public function matchExtension($extension)
        {
            if (isset($this->available_extensions[$extension])) {
                return true;
            } else {
                return $this->is_wildcard && $extension !== '';
            }
        }
    
        /**
         * @param  array   $param
         * @param  string  $ext
         * @param  boolean $strict
         * @return string
         */
        public function makePath(array $param, $ext, $strict)
        {
            $path = '';
    
            if ($strict) {
                $got_keys = array_keys($param);
                $expects  = array_values($this->param_pos);
                $diff     = array_diff($got_keys, $expects);
    
                if ($diff !== []) {
                    $json = json_encode(array_values($diff));
                    throw new \DomainException('unnecessary parameters: ' . $json);
                }
            }
    
            foreach ($this->split_path as $i => $pattern) {
                if (!isset($this->param_pos[$i])) {
                    $path .= '/' . $pattern;
                    continue;
                }
    
                $name = $this->param_pos[$i];
    
                if (!isset($param[$name]) || !preg_match($pattern, $param[$name], $matches)) {
                    throw new \DomainException("Error");
                }
    
                $path .= '/' . $param[$name];
            }
    
            if ($ext !== null && $ext !== '') {
                $path .= '.' . $ext;
            }
    
            return ($path === '') ? '/' : $path;
        }
    
        /**
         * @param  string   $method_str ex. "GET|POST"
         * @param  string   $path       ex. "/dir_name/path"
         * @param  mixed    $value
         * @param  string[] $ext
         * @param  array    $params
         * @return Action new instance object
         */
        public static function create($method_str, $path, $value, array $ext, array $params = [])
        {
            $methods = explode('|', $method_str);
            list($split_path, $param_pos)
                = self::parsePathParam($path, $params);
    
            return new Action($methods, $split_path, $param_pos, $ext, $value);
        }
    
        /**
         * @param  string $path
         * @param  array  $params
         * @return array  [$split_path, $param_pos]
         */
        public static function parsePathParam($path, array $params)
        {
            $split_path = array_values(array_filter(explode('/', $path), 'strlen'));
    
            if (!$params) { return [$split_path, []]; }
    
            $new_split_path = [];
            $param_pos = [];
            foreach ($split_path as $i => $p) {
                $variable = null;
    
                if (strpos($p, ':') !== false) {
                    $v = substr($p, 1);
                    if (isset($params[$v])) { $variable = $v; }
                }
    
                if ($variable === null) {
                    $new_split_path[] = $p;
                } else {
                    $param_pos[$i]    = $variable;
                    $new_split_path[] = $params[$v];
                }
            }
    
            return [$new_split_path, $param_pos];
        }
    
        /**
         * @param string[] $methods ex. ['GET', 'POST', 'PUT', 'DELETE']
         */
        public static function setHTTPMethod(array $methods)
        {
            self::$enum_values['methods'] = $methods;
        }
    
        protected static function assertMethods(array $methods)
        {
            foreach ($methods as $m) {
                self::assertValue('enum', 'methods', $m, false);
            }
        }
    }
    
    Teto Routing API documentation generated by ApiGen