-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathRouter.php
More file actions
139 lines (133 loc) · 5.74 KB
/
Copy pathRouter.php
File metadata and controls
139 lines (133 loc) · 5.74 KB
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
<?php
namespace Bricks\Cli\Routing;
/**
* Маршрутизирует запросы, используемые при вызове PHP интерпретатора из
* командной строки.
*
* Экземпляры данного класса позволяют описать маршруты обработки запросов и
* вызвать требуемые функции в зависимости от опций вызова.
*
* Пример установки анонимной функции-обработчика:
* $router = new Router;
* $router->route(
* [
* 'a' => '/^delete$/', // Если опция '-a' равна 'delete'
* 'id' => '/^[0-9]+$/' // и опция '--id' содержит целое число
* ],
* function($call){
* echo 'Delete ' . $call->opt('id');
* }
* );
* $router->run(new Call('a:', ['action:', 'id:']));
*
* Пример установки метода класса:
* $router = new Router;
* $router->route(
* [
* 'a' => '/^create$/',
* 'data' => '/^.+$/'
* ],
* 'createAction', // Вызов метода 'createAction'
* 'EntityController' // объекта класса 'EntityController'
* );
* $router->run(new Call('a:', ['action:', 'data:']));
*
* @author Artur Sh. Mamedbekov
*/
class Router{
/**
* @var array Карта маршрутизации в виде массива объектов следующей структуры:
* [
* pattern => шаблонОпций,
* callback => обработчик,
* context => контекстОбработчика
* ]
*/
private $map = [];
/**
* Вызывает указанную функцию в заданном контексте.
*
* @param Call $call Объект запроса.
* @param callable|string $callback Анонимная функция или имя целевой
* функции/метода.
* @param string|object|null $context Контекст вызова в виде объекта или имени
* класса, который будет инстанциирован.
*/
private function call(Call $call, $callback, $context){
if(!is_null($context)){
if(is_string($context)){
$context = new $context;
}
$callback = [$context, $callback];
}
return call_user_func_array($callback, [$call]);
}
/**
* Регистрирует маршрут.
*
* Пример маршрутизации запроса справки:
* $router = new Router;
* $router->route(
* ['a' => '/^help$/'], // Для вызова с опцией '-a' равной 'help'
* 'helpAction', // обработка методом 'helpAction'
* 'EntityController' // объекта класса 'EntityController'
* );
* $router->run(new Call('a:'));
*
* @param array $pattern Ассоциативный массив выражений, ключами которого
* выступают имена опций вызова, а значениями - требуемые значения этих опций
* в виде регулярного выражения. Если все опции перечисленные в этом массиве
* соответствуют регулярным выражениям, маршрут считается найденным.
* @param callable|string $callback Обработчик запроса в виде анонимной
* функции или имени функции.
* При вызове обработчику будет передан экземпляр класса Call, представляющий
* запрос.
* @param object|string $context [optional] Контекст вызова обработчика в виде
* объекта или имени класса, который будет инстанциирован.
*/
public function route(array $pattern, $callback, $context = null){
array_push($this->map, [
'pattern' => $pattern,
'callback' => $callback,
'context' => $context
]);
}
/**
* Выполняет поиск маршрута и вызов обработчика в случае успеха.
*
* Маршруты обрабатываются в порядке их регистрации, при этом обработка
* останавливается при нахождении первого подходящего маршрута.
* Пример обработки ошибки маршрутизации:
* $router = new Router;
* $router->route(['a' => '/^help$/'], 'helpAction', 'EntityController');
* try{
* $router->run(new Call('a:'));
* catch(RoutingException $e){
* echo 'Invalid action';
* return 1;
* }
*
* @param Call $call Объект запроса.
*
* @throws RoutingException Выбрасывается в случае ошибки маршрутизации
* (отсутствия подходящего обработчика запроса).
*
* @return mixed Данные, возвращаемые вызванным обработчиком.
*/
public function run(Call $call){
foreach($this->map as $options){
$success = true;
foreach($options['pattern'] as $opt => $pattern){
$opt = $call->opt($opt);
if(is_null($opt) || !preg_match($pattern, $opt)){
$success = false;
break;
}
}
if($success){
return $this->call($call, $options['callback'], $options['context']);
}
}
throw new RoutingException('Invalid call');
}
}