1
|
|
|
<?php namespace Comodojo\Dispatcher\Router; |
2
|
|
|
|
3
|
|
|
use \Comodojo\Exception\DispatcherException; |
4
|
|
|
use \Serializable; |
5
|
|
|
use \InvalidArgumentException; |
6
|
|
|
use \Exception; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* @package Comodojo Dispatcher |
10
|
|
|
* @author Marco Giovinazzi <[email protected]> |
11
|
|
|
* @author Marco Castiello <[email protected]> |
12
|
|
|
* @license GPL-3.0+ |
13
|
|
|
* |
14
|
|
|
* LICENSE: |
15
|
|
|
* |
16
|
|
|
* This program is free software: you can redistribute it and/or modify |
17
|
|
|
* it under the terms of the GNU Affero General Public License as |
18
|
|
|
* published by the Free Software Foundation, either version 3 of the |
19
|
|
|
* License, or (at your option) any later version. |
20
|
|
|
* |
21
|
|
|
* This program is distributed in the hope that it will be useful, |
22
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
23
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24
|
|
|
* GNU Affero General Public License for more details. |
25
|
|
|
* |
26
|
|
|
* You should have received a copy of the GNU Affero General Public License |
27
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
28
|
|
|
*/ |
29
|
|
|
|
30
|
|
|
class Route implements Serializable { |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @const string |
34
|
|
|
*/ |
35
|
|
|
const REDIRECT_REFRESH = 'REFRESH'; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @const string |
39
|
|
|
*/ |
40
|
|
|
const REDIRECT_LOCATION = 'LOCATION'; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var string |
44
|
|
|
*/ |
45
|
|
|
protected $type; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
protected $classname; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var int |
54
|
|
|
*/ |
55
|
|
|
protected $redirect_code; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var string |
59
|
|
|
*/ |
60
|
|
|
protected $redirect_location; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var string |
64
|
|
|
*/ |
65
|
|
|
protected $redirect_message; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var string |
69
|
|
|
*/ |
70
|
|
|
protected $redirect_type = self::REDIRECT_LOCATION; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @var int |
74
|
|
|
*/ |
75
|
|
|
protected $error_code; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @var string |
79
|
|
|
*/ |
80
|
|
|
protected $error_message; |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @var array |
84
|
|
|
*/ |
85
|
|
|
protected $parameters = []; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @var array |
89
|
|
|
*/ |
90
|
|
|
protected $service = []; |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @var array |
94
|
|
|
*/ |
95
|
|
|
protected $request = []; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @var array |
99
|
|
|
*/ |
100
|
|
|
protected $query = []; |
101
|
|
|
|
102
|
2 |
|
public function getType() { |
103
|
|
|
|
104
|
2 |
|
return $this->type; |
105
|
|
|
|
106
|
|
|
} |
107
|
|
|
|
108
|
2 |
|
public function setType($type) { |
109
|
|
|
|
110
|
2 |
|
$this->type = $type; |
111
|
|
|
|
112
|
2 |
|
return $this; |
113
|
|
|
|
114
|
|
|
} |
115
|
|
|
|
116
|
2 |
|
public function getClassName() { |
117
|
|
|
|
118
|
2 |
|
return $this->classname; |
119
|
|
|
|
120
|
|
|
} |
121
|
|
|
|
122
|
2 |
|
public function setClassName($class) { |
123
|
|
|
|
124
|
2 |
|
$this->classname = $class; |
125
|
|
|
|
126
|
2 |
|
return $this; |
127
|
|
|
|
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
public function getRedirectCode() { |
131
|
|
|
|
132
|
|
|
return $this->redirect_code; |
133
|
|
|
|
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
public function setRedirectCode($code) { |
137
|
|
|
|
138
|
|
|
if ( $code < 300 || $code >= 400 ) { |
139
|
|
|
throw new InvalidArgumentException("Invalid redirection code $code"); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
$this->redirect_code = $code; |
143
|
|
|
|
144
|
|
|
return $this; |
145
|
|
|
|
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
public function getRedirectLocation() { |
149
|
|
|
|
150
|
|
|
return $this->redirect_location; |
151
|
|
|
|
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
public function setRedirectLocation($location) { |
155
|
|
|
|
156
|
|
|
$this->redirect_location = $location; |
157
|
|
|
|
158
|
|
|
return $this; |
159
|
|
|
|
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
public function getRedirectMessage() { |
163
|
|
|
|
164
|
|
|
return $this->redirect_message; |
165
|
|
|
|
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
public function setRedirectMessage($message) { |
169
|
|
|
|
170
|
|
|
$this->redirect_message = $message; |
171
|
|
|
|
172
|
|
|
return $this; |
173
|
|
|
|
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
public function getRedirectType() { |
177
|
|
|
|
178
|
|
|
return $this->redirect_type; |
179
|
|
|
|
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
public function setRedirectType($type) { |
183
|
|
|
|
184
|
|
|
if ( !in_array($type, [self::REDIRECT_REFRESH, self::REDIRECT_LOCATION]) ) { |
185
|
|
|
throw new InvalidArgumentException("Invalid redirection type $type"); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$this->redirect_type = $type; |
189
|
|
|
|
190
|
|
|
return $this; |
191
|
|
|
|
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
public function getErrorCode() { |
195
|
|
|
|
196
|
|
|
return $this->error_code; |
197
|
|
|
|
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
public function setErrorCode($code) { |
201
|
|
|
|
202
|
|
|
if ( $code < 400 || $code >= 600 ) { |
203
|
|
|
throw new InvalidArgumentException("Invalid error code $code"); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
$this->error_code = $code; |
207
|
|
|
|
208
|
|
|
return $this; |
209
|
|
|
|
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
public function getErrorMessage() { |
213
|
|
|
|
214
|
|
|
return $this->error_message; |
215
|
|
|
|
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
public function setErrorMessage($message) { |
219
|
|
|
|
220
|
|
|
$this->error_message = $message; |
221
|
|
|
|
222
|
|
|
return $this; |
223
|
|
|
|
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
public function getParameter($key) { |
227
|
|
|
|
228
|
|
|
$parameters = $this->parameters; |
229
|
|
|
|
230
|
|
|
return isset($parameters[$key]) ? $parameters[$key] : null; |
231
|
|
|
|
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
public function getParameters() { |
235
|
|
|
|
236
|
|
|
return $this->parameters; |
237
|
|
|
|
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
public function setParameter($key, $value) { |
241
|
|
|
|
242
|
|
|
$this->parameters = array_merge($this->parameters, array($key => $value)); |
243
|
|
|
|
244
|
|
|
return $this; |
245
|
|
|
|
246
|
|
|
} |
247
|
|
|
|
248
|
1 |
|
public function setParameters($parameters) { |
249
|
|
|
|
250
|
1 |
|
$this->parameters = $parameters; |
251
|
|
|
|
252
|
1 |
|
return $this; |
253
|
|
|
|
254
|
|
|
} |
255
|
|
|
|
256
|
1 |
|
public function getRequestParameter($key) { |
257
|
|
|
|
258
|
1 |
|
$parameters = $this->request; |
259
|
|
|
|
260
|
1 |
|
return isset($parameters[$key]) ? $parameters[$key] : null; |
261
|
|
|
|
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
public function getService() { |
265
|
|
|
|
266
|
|
|
return $this->service; |
267
|
|
|
|
268
|
|
|
} |
269
|
|
|
|
270
|
1 |
|
public function getServiceName() { |
271
|
|
|
|
272
|
1 |
|
return empty($this->service) ? "default" : implode('.', $this->service); |
273
|
|
|
|
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
public function setService($service) { |
277
|
|
|
|
278
|
|
|
$this->service = $service; |
279
|
|
|
|
280
|
|
|
return $this; |
281
|
|
|
|
282
|
|
|
} |
283
|
|
|
|
284
|
1 |
|
public function addService($service) { |
285
|
|
|
|
286
|
1 |
|
$this->service = array_merge($this->service, array($service)); |
287
|
|
|
|
288
|
1 |
|
return $this; |
289
|
|
|
|
290
|
|
|
} |
291
|
|
|
|
292
|
1 |
|
public function getRequestParameters() { |
293
|
|
|
|
294
|
1 |
|
return $this->request; |
295
|
|
|
|
296
|
|
|
} |
297
|
|
|
|
298
|
1 |
|
public function setRequestParameter($key, $value) { |
299
|
|
|
|
300
|
1 |
|
$this->request = array_merge($this->request, array($key => $value)); |
301
|
|
|
|
302
|
1 |
|
return $this; |
303
|
|
|
|
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
public function setRequestParameters($parameters) { |
307
|
|
|
|
308
|
|
|
$this->request = $parameters; |
309
|
|
|
|
310
|
|
|
return $this; |
311
|
|
|
|
312
|
|
|
} |
313
|
|
|
|
314
|
1 |
|
public function setQuery($key, $regex, $required = false) { |
315
|
|
|
|
316
|
1 |
|
$this->query = array_merge($this->query, [ |
317
|
|
|
$key => [ |
318
|
1 |
|
"regex" => $regex, |
319
|
|
|
"required" => $required |
320
|
1 |
|
] |
321
|
1 |
|
]); |
322
|
|
|
|
323
|
1 |
|
return $this; |
324
|
|
|
|
325
|
|
|
} |
326
|
|
|
|
327
|
1 |
View Code Duplication |
public function isQueryRequired($key) { |
|
|
|
|
328
|
|
|
|
329
|
1 |
|
$query = $this->query; |
330
|
|
|
|
331
|
1 |
|
return isset($query[$key]) ? $query[$key]["required"] : false; |
332
|
|
|
|
333
|
|
|
} |
334
|
|
|
|
335
|
1 |
View Code Duplication |
public function getQueryRegex($key) { |
|
|
|
|
336
|
|
|
|
337
|
1 |
|
$query = $this->query; |
338
|
|
|
|
339
|
1 |
|
return isset($query[$key]) ? $query[$key]["regex"] : null; |
340
|
|
|
|
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
public function getQueries() { |
344
|
|
|
|
345
|
|
|
return $this->query; |
346
|
|
|
|
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
public function setQueries($query) { |
350
|
|
|
|
351
|
|
|
$this->query = $query; |
352
|
|
|
|
353
|
|
|
return $this; |
354
|
|
|
|
355
|
|
|
} |
356
|
|
|
|
357
|
1 |
|
public function path($path) { |
358
|
|
|
|
359
|
|
|
// Because of the nature of the global regular expression, all the bits of the matched route are associated with a parameter key |
360
|
1 |
|
foreach ($this->query as $key => $value) { |
361
|
|
|
|
362
|
1 |
|
if ( isset($path[$key]) ) { |
363
|
|
|
/* if it's available a bit associated with the parameter name, it is compared against |
364
|
|
|
* it's regular expression in order to extrect backreferences |
365
|
|
|
*/ |
366
|
1 |
|
if ( preg_match('/^' . $value['regex'] . '$/', $path[$key], $matches) ) { |
367
|
|
|
|
368
|
1 |
|
if ( count($matches) == 1 ) $matches = $matches[0]; // This is the case where no backreferences are present or available. |
369
|
|
|
|
370
|
|
|
// The extracted value (with any backreference available) is added to the query parameters. |
371
|
1 |
|
$this->setRequestParameter($key, $matches); |
372
|
|
|
|
373
|
1 |
|
} |
374
|
|
|
|
375
|
1 |
|
} elseif ($value['required']) { |
376
|
|
|
|
377
|
|
|
throw new DispatcherException(sprintf("Required parameter '%s' not specified.", $key), 1, null, 500); |
378
|
|
|
|
379
|
|
|
} |
380
|
|
|
|
381
|
1 |
|
} |
382
|
|
|
|
383
|
1 |
|
return $this; |
384
|
|
|
|
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* Return the serialized data |
389
|
|
|
* |
390
|
|
|
* @return string |
391
|
|
|
*/ |
392
|
|
|
public function serialize() { |
393
|
|
|
|
394
|
|
|
return serialize( (object) [ |
395
|
|
|
'classname' => $this->classname, |
396
|
|
|
'type' => $this->type, |
397
|
|
|
'service' => $this->service, |
398
|
|
|
'parameters' => $this->parameters, |
399
|
|
|
'request' => $this->request, |
400
|
|
|
'query' => $this->query |
401
|
|
|
]); |
402
|
|
|
|
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* Return the unserialized object |
407
|
|
|
* |
408
|
|
|
* @param string $data Serialized data |
409
|
|
|
* |
410
|
|
|
*/ |
411
|
|
|
public function unserialize($data) { |
412
|
|
|
|
413
|
|
|
$parts = unserialize($data); |
414
|
|
|
|
415
|
|
|
$this->classname = $parts->classname; |
416
|
|
|
$this->type = $parts->type; |
417
|
|
|
$this->service = $parts->service; |
418
|
|
|
$this->parameters = $parts->parameters; |
419
|
|
|
$this->request = $parts->request; |
420
|
|
|
$this->query = $parts->query; |
421
|
|
|
|
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
} |
425
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.