Completed
Push — master ( 44915f...538059 )
by Luka
03:46
created

Router::__set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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