1: <?php
2: namespace codemania\core;
3: /**
4: * CodeMania Content Manager Framework
5: *
6: * @author CodeMania Team <team@codemania.ru>
7: * @package CodeMania CMF
8: * @version 1.0.0
9: * @copyright (c) 2012, CodeMania Team
10: * @link http://codemania.ru
11: * @license http://codemania.ru/license.html
12: */
13: defined('CM_ROOT') or exit('Запрет доступа!');
14: /**
15: * Роутер
16: */
17: class Route extends Singleton {
18: /**
19: * Контроллер по-умолчанию
20: * @var string
21: */
22: static protected $_default;
23: /**
24: * Правила роутинга
25: * @var array
26: */
27: static private $_rules = array();
28: /**
29: * Массив шаблонов для замены
30: * @var array
31: */
32: static private $_repl = array(
33: array(':int', ':str'),
34: array('[0-9]*', '.+'),
35: );
36: /**
37: * Массив ключей => значений сегментов
38: * @var array
39: */
40: static private $_routes = array();
41: /**
42: * Сохраняет контроллер по умолчанию
43: * @param string $controller Имя контроллера
44: */
45: static public function set_controller($controller) {
46: self::$_default = (string)ucfirst($controller);
47: }
48: /**
49: * Сохраняет правила роутинга
50: * @param array $rules Правила роутинга
51: */
52: static public function set_rules(array $rules) {
53: self::$_rules = $rules;
54: }
55: /**
56: * Возвращает значение сегмента по ключу
57: * См. Route->_routes_combine();
58: * @param string $name Ключ сегмента
59: * @return string Значение сегмента по ключу
60: * или false в случаее его отсутствия
61: */
62: static public function get($name) {
63: // Если ключ не существует возвращаем false
64: return isset(self::$_routes[(string)$name]);
65: }
66: /**
67: * Обработанная строка URI
68: * @var string
69: */
70: private $_uri_string;
71: /**
72: * Массив сегментов
73: * @var array
74: */
75: protected $_segments = array();
76: /**
77: * Определяет сегменты
78: * @param string $uri_string Обработанная строка URI
79: */
80: public function __construct($uri_string) {
81: // Записываем строку в обьект класса
82: $this->_uri_string = (string)$uri_string;
83: // Если строка не обработалась чесрез правила
84: if ( ! $this->_execute_rules()) {
85: // То просто разбиваем ее на сегменты
86: $this->_fetch_segments();
87: }
88: // Комбинируем роуты
89: $this->_routes_combine();
90: }
91: /**
92: * @author ExpressionEngine Dev Team
93: * @package CodeIgniter
94: * Обрабатывает URI по правилу
95: * @return boolean true в случае успешной обработки false в случае неудачи
96: */
97: private function _execute_rules() {
98: // Если в массиве $_rules есть хоть одно правило
99: if (count(self::$_rules) > 0) {
100: //
101: foreach (self::$_rules as $key => $val) {
102: // Обрабатываем условное правило в Perl-совместимое
103: $key = str_replace(self::$_repl[0], self::$_repl[1], $key);
104: // Проверяем соответствие строки правилу
105: if (preg_match('#^'.$key.'$#', $this->_uri_string)) {
106: // Если в строке не найдены элементы правил
107: if ((strpos($val, '$') && strpos($key, '(')) === false) {
108: // Возвращаем отрицательный результат
109: return false;
110: }
111: // Обрабатываем строку получившимся правилом
112: $val = preg_replace('#^'.$key.'$#', $val, $this->_uri_string);
113: // Разбиваем строку на сегменты
114: $this->_segments = explode('/', $val);
115: // Возвращаем положительный результат
116: return true;
117: }
118: }
119: }
120: // Возвращаем отрицательный результат
121: return false;
122: }
123: /**
124: * Разбивает строку на сегменты
125: */
126: private function _fetch_segments() {
127: $this->_segments = explode('/', $this->_uri_string);
128: }
129: /**
130: * Комбинирует из сегментов массив ключ => значение
131: * Например из строки /edit/user/id/111/
132: * функция вернет массив
133: * array(
134: * 'edit' => 'user',
135: * 'id' => '111'
136: * )
137: */
138: private function _routes_combine() {
139: // Ключи
140: $keys = array();
141: // Значения
142: $values = array();
143: foreach ($this->_segments as $key => $val) {
144: // Если ключ четный
145: if ($key % 2) {
146: // Записываем его в массив значений
147: $values[] = $val;
148: } else {
149: // А если нет в массив ключей
150: $keys[] = $val;
151: }
152: }
153: // Если количество ключей равно количесву значений
154: if (count($keys) === count($values)) {
155: // Комбинируем единый массив
156: self::$_routes = array_combine($keys, $values);
157: }
158: }
159: }