Completed
Push — master ( 8bfbde...aef338 )
by Damien
03:45
created

Route::matches()   D

Complexity

Conditions 9
Paths 6

Size

Total Lines 37
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 2
Metric Value
c 3
b 0
f 2
dl 0
loc 37
rs 4.909
cc 9
eloc 16
nc 6
nop 1
1
<?php
2
/**
3
 * Veto.
4
 * PHP Microframework.
5
 *
6
 * @author Damien Walsh <[email protected]>
7
 * @copyright Damien Walsh 2013-2014
8
 * @version 0.1
9
 * @package veto
10
 */
11
namespace Veto\Layer\Router;
12
use Veto\HTTP\Request;
13
14
/**
15
 * Route
16
 * Represents a route within the application.
17
 *
18
 * @since 0.1
19
 */
20
class Route
21
{
22
    /**
23
     * The pattern to match.
24
     *
25
     * @var string
26
     */
27
    protected $pattern;
28
29
    /**
30
     * Any regex rules to apply to placeholders within $pattern.
31
     *
32
     * @var string[]
33
     */
34
    protected $rules;
35
36
    /**
37
     * The name of the route.
38
     *
39
     * @var string
40
     */
41
    protected $name;
42
43
    /**
44
     * A list of supported methods.
45
     *
46
     * @var string[]
47
     */
48
    protected $methods;
49
50
    /**
51
     * The controller that handles the route.
52
     *
53
     * @var string
54
     */
55
    protected $controller;
56
57
    /**
58
     * The action that handles the route.
59
     *
60
     * @var string
61
     */
62
    protected $action;
63
64
    /**
65
     * Create a new route.
66
     *
67
     * @param string $name The name of the route.
68
     * @param string $pattern The route pattern string.
69
     * @param string[] $rules Any regex rules to apply to placeholders in $pattern.
70
     * @param string[] $methods The methods that can be used for this route.
71
     * @param string $controller The controller that handles the route.
72
     * @param string $action The action that handles the route.
73
     */
74
    public function __construct($name, $pattern, array $rules, array $methods, $controller, $action)
75
    {
76
        // Validate the rules
77
        foreach ($rules as $parameter => $rule) {
78
            if (@preg_match('@' . $rule . '@', null) === false) {
79
                throw new \InvalidArgumentException(
80
                    sprintf('Rule for parameter %s of route %s is not a valid regex string.', $name, $parameter)
81
                );
82
            }
83
        }
84
85
        $this->name = $name;
86
        $this->pattern = $pattern;
87
        $this->rules = $rules;
88
        $this->methods = $methods;
89
        $this->controller = $controller;
90
        $this->action = $action;
91
    }
92
93
    /**
94
     * Check if the request matches a defined route pattern.
95
     *
96
     * Returns an array containing any route parameters on a successful match.
97
     * Returns false for failed matches.
98
     *
99
     * @param Request $request The request to check.
100
     * @return array|bool
101
     */
102
    public function matches(Request $request)
103
    {
104
        // Verify that the method is appropriate
105
        if (count($this->methods) > 0 && !in_array($request->getMethod(), $this->methods)) {
106
            return false;
107
        }
108
109
        // Check if the pattern contains any {...} blocks
110
        preg_match_all('@{([A-Za-z_]+)}@', $this->pattern, $placeholders);
111
112
        if ($placeholders && isset($placeholders[1])) {
113
114
            // Build an array of replacement regexes
115
            $replacementRegexes = $targetRegexes = array();
116
            foreach ($placeholders[1] as $placeholder) {
117
                $targetRegexes[] = '@{[A-Za-z_]+}@';
118
                $replacementRegexes[] =
119
                    array_key_exists($placeholder, $this->rules) ? '(' . $this->rules[$placeholder] . ')' : '([^/]+)';
120
            }
121
122
            // Convert all {...} blocks into regex groups
123
            $pattern = preg_replace($targetRegexes, $replacementRegexes, $this->pattern);
124
125
            // Get the placeholder names
126
            $placeholders = $placeholders[1];
127
128
            // See if the route matches
129
            if (preg_match('@^' . $pattern . '$@', $request->getUri()->getPath(), $matches)) {
130
                // Merge the placeholder names with their URI values
131
                array_shift($matches);
132
                return array_combine($placeholders, $matches);
133
            }
134
        }
135
136
        // Simple matching - check if the URI matches the pattern
137
        return $request->getUri() == $this->pattern ? array() : false;
138
    }
139
140
141
    /**
142
     * Generate a URL from a route name and parameter set.
143
     *
144
     * @param array $parameters Optionally the parameters to use.
145
     * @throws \Exception
146
     * @return string|boolean The URL on success, false on failure.
147
     */
148
    public function generateUrl(array $parameters = array())
149
    {
150
        $url = $this->pattern;
151
152
        // Get each of the {...} blocks in the URL
153
        preg_match_all('@{([A-Za-z_]+)}@', $url, $placeholders);
154
155
        // Swap all the parameters
156
        foreach ($placeholders[1] as $placeholder) {
157
158
            if (!array_key_exists($placeholder, $parameters)) {
159
                throw new \Exception(
160
                    'Parameter "' . $placeholder . '" must be specified to ' .
161
                    'generate URL for route "' . $this->name . '"'
162
                );
163
            }
164
165
            // Replace it with the value from the array
166
            $url = str_replace('{' . $placeholder . '}', $parameters[$placeholder], $url);
167
        }
168
169
        return $url;
170
    }
171
172
    /**
173
     * @param string $action
174
     */
175
    public function setAction($action)
176
    {
177
        $this->action = $action;
178
    }
179
180
    /**
181
     * @return string
182
     */
183
    public function getAction()
184
    {
185
        return $this->action;
186
    }
187
188
    /**
189
     * @param string $controller
190
     */
191
    public function setController($controller)
192
    {
193
        $this->controller = $controller;
194
    }
195
196
    /**
197
     * @return string
198
     */
199
    public function getController()
200
    {
201
        return $this->controller;
202
    }
203
204
    /**
205
     * @param string $pattern
206
     */
207
    public function setPattern($pattern)
208
    {
209
        $this->pattern = $pattern;
210
    }
211
212
    /**
213
     * @return string
214
     */
215
    public function getPattern()
216
    {
217
        return $this->pattern;
218
    }
219
220
    /**
221
     * @param string $name
222
     */
223
    public function setName($name)
224
    {
225
        $this->name = $name;
226
    }
227
228
    /**
229
     * @return string
230
     */
231
    public function getName()
232
    {
233
        return $this->name;
234
    }
235
236
    /**
237
     * @param string[] $methods
238
     */
239
    public function setMethods($methods)
240
    {
241
        $this->methods = $methods;
242
    }
243
244
    /**
245
     * @return string[]
246
     */
247
    public function getMethods()
248
    {
249
        return $this->methods;
250
    }
251
}
252