startPoint = $mountPoint; } /** * @param array $rules */ public function withRules(array $rules): void { $this->rules = []; foreach ($rules as $rulesKey => $rulesNode) { if (!isset($rulesNode['key'], $rulesNode['routes'])) continue; // преобразуем псевдомаску в реальную маску // заменяем алиасы на регвыражения $realPattern = $rulesNode['key']; $realPattern = preg_replace("'<([A-z0-9_]+?):@any>'", "(?P<$1>.*)", $realPattern); $realPattern = preg_replace("'<([A-z0-9_]+?):@num>'", "(?P<$1>[0-9]+)", $realPattern); $realPattern = preg_replace("'<([A-z0-9_]+?):@path>'", "(?P<$1>[^/]+)", $realPattern); // поддерживаем свободное регулярное выражение в псевдомаске $realPattern = preg_replace("'<([A-z0-9_]+?):(.+?)>'", "(?P<$1>$2)", $realPattern); // заменяем алиасы на регвыражения $realPattern = str_replace(["<@any>", "<@num>", "<@path>"], [".*", "[0-9]+", "[^/]+"], $realPattern); // при наличии слеша в конце правила url должно строго ему соответствовать $end = (str_ends_with($realPattern, "/")) ? "$" : ""; // меняем запись на паттерн $this->rules[$rulesKey] = $rulesNode; $this->rules[$rulesKey]['key'] = "'^".$realPattern.$end."'"; } } /** * @param array $rules * @return void */ public function withSet(array $rules): void { $this->rules = []; foreach ($rules as $rulesKey => $rulesNode) { if(!isset($rulesNode['key'], $rulesNode['routes'])) continue; $rulesNode['key'] = trim($rulesNode['key'], '/'); if(!preg_match("'^[A-z0-9_/]+$'", $rulesNode['key'])) continue; $this->rules[$rulesKey] = $rulesNode; } } /** * @param RequestInterface $request * @return array|null */ public function match(RequestInterface $request): ?array { foreach ($this->rules as $rule) { // если для правила определен метод и он не совпал смотри далее if(!empty($rule['withMethod']) && is_array($rule['withMethod']) && false === (array_search($request->getMethod(), $rule['withMethod']))) continue; if(!empty($rule['withoutMethod']) && is_array($rule['withoutMethod']) && false !== (array_search($request->getMethod(), $rule['withoutMethod']))) continue; // вычисляем рабочий url $currentUrlString = preg_replace("'^".preg_quote($this->startPoint)."'", "/", $request->getUri()->getPath()); // в цикле проверяем совпадения текущей строки с правилами if (preg_match($rule['key'], $currentUrlString, $matches)) { $routes = []; foreach ($rule['routes'] as $route) { // если в результате есть именные ключи от ?P, пытаемся произвести замену в части inc foreach ($matches as $matchesKey => $matchesVal) { if (!is_numeric($matchesKey)) { $route['action'] = str_replace("<".$matchesKey.">", ucfirst($matchesVal), $route['action']); $route['method'] = str_replace("<".$matchesKey.">", ucfirst($matchesVal), $route['method']); if (!empty($route['params'])) { $route['params'] = str_replace("<".$matchesKey.">", $matchesVal, $route['params']); } } } // чистка маркеров $route['action'] = preg_replace("'<.+>'", "", $route['action']); $route['method'] = preg_replace("'<.+>'", "", $route['method']); if (!empty($route['params'])) { $route['params'] = preg_replace("'<.+>'", "", $route['params']); } $className = (!empty($route['action'])) ? $route['action'] : ""; $methodName = (!empty($route['method'])) ? $route['method'] : ""; $paramSet = (!empty($route['params'])) ? explode(",",str_replace(" ", "", $route['params'])) : []; $params = []; foreach ($paramSet as $key => $param){ if(empty($param)) continue; $params[$key] = (preg_match("'^[0-9]+$'", $param)) ? (int) $param : $param; } $routes[] = new MatchObject($className, $methodName, $params); } return $routes; } } return null; } /** * @param RequestInterface $request * @return array|null */ public function matchByArgv(RequestInterface $request): ?array { foreach ($this->rules as $rule) { // вычисляем строку для поиска $currentString = trim(preg_replace("'^".preg_quote($this->startPoint)."/'", "", $request->getServerParams()['argv'][1]),'/'); // в цикле проверяем совпадения текущей строки с правилами if ($rule['key'] == $currentString) { $routes = []; foreach ($rule['routes'] as $route) { $className = (!empty($route['action'])) ? $route['action'] : ""; $methodName = (!empty($route['method'])) ? $route['method'] : ""; $params = []; foreach ($request->getServerParams()['argv'] as $key => $param){ if($key < 2) continue; $params[$key] = (preg_match("'^[0-9]+$'", $param)) ? (int) $param : $param; } $routes[] = new MatchObject($className, $methodName, $params); } return $routes; } } return null; } }