Host::_link()   B
last analyzed

Complexity

Conditions 10
Paths 10

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 10.4632

Importance

Changes 0
Metric Value
cc 10
eloc 20
c 0
b 0
f 0
nc 10
nop 2
dl 0
loc 29
ccs 10
cts 12
cp 0.8333
crap 10.4632
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Lead\Router;
3
4
/**
5
 * The Route class.
6
 */
7
class Host
8
{
9
    /**
10
     * Class dependencies.
11
     *
12
     * @var array
13
     */
14
    protected $_classes = [];
15
16
    /**
17
     * The matching scheme.
18
     *
19
     * @var string
20
     */
21
    protected $_scheme = '*';
22
23
    /**
24
     * The matching host.
25
     *
26
     * @var string
27
     */
28
    protected $_pattern = '*';
29
30
    /**
31
     * The tokens structure extracted from host's pattern.
32
     *
33
     * @see Parser::tokenize()
34
     * @var array
35
     */
36
    protected $_token = null;
37
38
    /**
39
     * The host's regular expression pattern.
40
     *
41
     * @see Parser::compile()
42
     * @var string
43
     */
44
    protected $_regex = null;
45
46
    /**
47
     * The host's variables.
48
     *
49
     * @see Parser::compile()
50
     * @var array
51
     */
52
    protected $_variables = null;
53
54
    /**
55
     * Constructs a route
56
     *
57
     * @param array $config The config array.
58
     */
59
    public function __construct($config = [])
60
    {
61
        $defaults = [
62
            'scheme'     => '*',
63
            'pattern'     => '*',
64
            'classes'    => [
65
                'parser' => 'Lead\Router\Parser'
66
            ]
67 20
        ];
68 20
        $config += $defaults;
69
70 20
        $this->_classes = $config['classes'];
71
72 20
        $this->scheme($config['scheme']);
73 20
        $this->pattern($config['pattern']);
74
    }
75
76
    /**
77
     * Get/sets the host's scheme.
78
     *
79
     * @param  string      $scheme The scheme on set or none to get the setted one.
80
     * @return string|self         The scheme on get or `$this` on set.
81
     */
82
    public function scheme($scheme = null)
83
    {
84
        if (!func_num_args()) {
85 18
            return $this->_scheme;
86
        }
87 20
        $this->_scheme = $scheme;
88 20
        return $this;
89
    }
90
91
    /**
92
     * Get/sets the host's pattern.
93
     *
94
     * @param  string      $pattern The pattern on set or none to get the setted one.
95
     * @return string|self          The pattern on get or `$this` on set.
96
     */
97
    public function pattern($pattern = null)
98
    {
99
        if (!func_num_args()) {
100 12
            return $this->_pattern;
101
        }
102 20
        $this->_token = null;
103 20
        $this->_regex = null;
104 20
        $this->_variables = null;
105 20
        $this->_pattern = $pattern;
106 20
        return $this;
107
    }
108
109
    /**
110
     * Returns the route's token structures.
111
     *
112
     * @return array A collection route's token structure.
113
     */
114
    public function token()
115
    {
116
        if ($this->_token === null) {
117 16
            $parser = $this->_classes['parser'];
118 16
            $this->_token = [];
119 16
            $this->_regex = null;
120 16
            $this->_variables = null;
121 16
            $this->_token = $parser::tokenize($this->_pattern, '.');
122
        }
123 16
        return $this->_token;
124
    }
125
126
    /**
127
     * Gets the route's regular expression pattern.
128
     *
129
     * @return string the route's regular expression pattern.
130
     */
131
    public function regex()
132
    {
133
        if ($this->_regex !== null) {
134 6
            return $this->_regex;
135
        }
136 10
        $this->_compile();
137 10
        return $this->_regex;
138
    }
139
140
    /**
141
     * Gets the route's variables and their associated pattern in case of array variables.
142
     *
143
     * @return array The route's variables and their associated pattern.
144
     */
145
    public function variables()
146
    {
147
        if ($this->_variables !== null) {
148 10
            return $this->_variables;
149
        }
150 6
        $this->_compile();
151 6
        return $this->_variables;
152
    }
153
154
    /**
155
     * Compiles the host's patten.
156
     */
157
    protected function _compile()
158
    {
159
        if ($this->pattern() === '*') {
160 4
            return;
161
        }
162 10
        $parser = $this->_classes['parser'];
163 10
        $rule = $parser::compile($this->token());
164 10
        $this->_regex = $rule[0];
165 10
        $this->_variables = $rule[1];
166
    }
167
168
    /**
169
     * Checks if a host matches a host pattern.
170
     *
171
     * @param  string  $host          The host to check.
172
     * @param  string  $hostVariables The matches host variables
173
     * @return boolean                Returns `true` on success, false otherwise.
174
     */
175
    public function match($request, &$hostVariables = null)
176
    {
177
        $defaults = [
178
            'host'   => '*',
179
            'scheme' => '*'
180 10
        ];
181 10
        $request += $defaults;
182 10
        $scheme = $request['scheme'];
183 10
        $host = $request['host'];
184
185 10
        $hostVariables = [];
186
187 10
        $anyHost = $this->pattern() === '*' || $host === '*';
188 10
        $anyScheme = $this->scheme() === '*' || $scheme === '*';
189
190
191
        if ($anyHost) {
192
            if ($this->variables()) {
193 2
                $hostVariables = array_fill_keys(array_keys($this->variables()), null);
194
            }
195 4
            return $anyScheme || $this->scheme() === $scheme;
196
        }
197
198
        if (!$anyScheme && $this->scheme() !== $scheme) {
199 2
            return false;
200
        }
201
202
        if (!preg_match('~^' . $this->regex() . '$~', $host, $matches)) {
203 6
            $hostVariables = null;
204 6
            return false;
205
        }
206 8
        $i = 0;
207
208
        foreach ($this->variables() as $name => $pattern) {
209 8
            $hostVariables[$name] = $matches[++$i];
210
        }
211 8
        return true;
212
    }
213
214
    /**
215
     * Returns the host's link.
216
     *
217
     * @param  array  $params  The host parameters.
218
     * @param  array  $options Options for generating the proper prefix. Accepted values are:
219
     *                         - `'scheme'`   _string_ : The scheme.
220
     *                         - `'host'`     _string_ : The host name.
221
     * @return string          The link.
222
     */
223
    public function link($params = [], $options = [])
224
    {
225
        $defaults = [
226
            'scheme'   => $this->scheme()
227 6
        ];
228 6
        $options += $defaults;
229
230
        if (!isset($options['host'])) {
231 6
            $options['host'] = $this->_link($this->token(), $params);
232
        }
233
234 6
        $scheme = $options['scheme'] !== '*' ? $options['scheme'] . '://' : '//';
235 6
        return $scheme . $options['host'];
236
    }
237
238
    /**
239
     * Helper for `Host::link()`.
240
     *
241
     * @param  array  $token    The token structure array.
242
     * @param  array  $params   The route parameters.
243
     * @return string           The URL path representation of the token structure array.
244
     */
245
    protected function _link($token, $params)
246
    {
247 6
        $link = '';
248
        foreach ($token['tokens'] as $child) {
249
            if (is_string($child)) {
250 6
                $link .= $child;
251 6
                continue;
252
            }
253
            if (isset($child['tokens'])) {
254
                if ($child['repeat']) {
255 2
                    $name = $child['repeat'];
256 2
                    $values = isset($params[$name]) && $params[$name] !== null ? (array) $params[$name] : [];
257
                    foreach ($values as $value) {
258 2
                        $link .= $this->_link($child, [$name => $value] + $params);
259
                    }
260
                } else {
261
                    $link .= $this->_link($child, $params);
262
                }
263 2
                continue;
264
            }
265
            if (!array_key_exists($child['name'], $params)) {
266
                if (!$token['optional']) {
267 2
                    throw new RouterException("Missing parameters `'{$child['name']}'` for host: `'{$this->_pattern}'`.");
268
                }
269
                return '';
270
            }
271 6
            $link .= $params[$child['name']];
272
        }
273 6
        return $link;
274
    }
275
}