Самодельный роутер неправильно работает

malina95

Дракула кода:)
Привет! Тут проблема одна появилась, поможете исправить?

PHP:
<?php
	
	namespace Core;
	
	class FrontController {
		
		private $defaultController = 'IndexController';
		private $defaultModel = 'IndexModel';
        private $defaultAction = 'indexAction';
		
		private function getRequestUri () {
			return $_SERVER['REQUEST_URI'];
		}
		
		public function Start () {
			
			$uri = $this->getRequestUri();
			
			//admin/editusers/id/1 - так выгледит строка запроса
            
			$splits = explode('/', trim($uri, '/'));
            
			//Выбор контроллера
            
			$controller = !empty($splits[0]) ? ucfirst($splits[0]).'Controller' : $this->defaultController;
			
			// Выбор модели если существует
            
			$model = !empty($splits[0]) ? ucfirst($splits[0]).'Model' : $this->defaultModel;
			
			//Выбор экшена
            
			$action = !empty($splits[1]) ? $splits[1].'Action' : $this->defaultAction;
            
			//выбор параметров
            
			if (!empty($splits[2])) {
                $keys = $values = array();
                for ($i = 2, $cnt = count($splits); $i < $cnt; $i++) {
                    if ($i % 2 == 0)
                        $keys[] = $splits[$i];
                    else
                        $values[]= $splits[$i];
                }
                if ($keys and $values)
                    $params = array_combine($keys, $values);
            }
			else $params = false;
            if (file_exists('App/Models/'.$model.'.php')) {
				include 'App/Models/'.$model.'.php';
				if (class_exists($model)) {
					$model = new $model();
				}
				else die('Класса не существует');
			}
			else die('Класса не существует');
			if (file_exists('App/Controllers/'.$controller.'.php')) {
				include 'App/Controllers/'.$controller.'.php';
				if (class_exists($controller)) {
					$controller = new $controller($model);
					if (method_exists($controller, $action)) {
						$controller = $controller->$action($params);
						return $controller;
					}
					else Functions::error404();
				}
				else die('Класса не существует');
			}
			else Functions::error404();
			
		}
		
	}
	
?>
Вообщем, я заметил очень сильный баг, или это не баг, пока не уверен...

При запросе test/index/ открывается контроллер IndexController, при запросе test/index/index/ открывается контроллер IndexController и метод indexAction(), но если запрос такой:

http://test/index/index/index/index/index/index/index/

то выскакивает ошибка:

Warning: array_combine() [function.array-combine]: Both parameters should have an equal number of elements in C:\OpenServer\domains\test\Core\FrontController.php on line 46
http://test/


а если запрос такой:

http://test/index/index/index/index/index/index/index/index/

то всё нормально, так вот как исправить такое множество параметров, как узнать сколько методу нужно аргументов?

ошибку я как нибудь сам исправлю... помогите пожалуйста
 

hell0w0rd

Продвинутый новичок
У вас ошибка в том, что строка должна четко совпадать с ее паттерном.
То есть если у вас example.com/index/{action} - то в action помещается ровно все что идет дальше.
 

keltanas

marty cats
А нужно ли такое велосипедное решение? Которое еще ничего не умеет, а уже доставляет проблемы?
Может попробовать что-то готовое? Пока не стало поздно?

Обычно ориентируются на карту маршрутов, хранящуюся в конфиге, базе или еще где. И ищут либо жесткое совпадение, либо по регулярному выражению.

А проверка существования экшена уже в последнюю очередь.
И любая не удачная проверка должна выдавать Functions::error404(). А что такое die(...) и зачем так делать вообще не понятно.
 
  • Like
Реакции: AmdY

AmdY

Пью пиво
Команда форума
malina95
это не баг, это фича. твой роутинг не предполагает такую комбинацию, поэтому просто супер что он вываливает ошибку. незачем в урлы добавлять дубли.

Практика передовать параметры /parameter/value - ужасна, для этого есть GET. сам бользовался, пока не осознал, что в 99% это не нужно, к ЧПУ это никакого отношения не имеет, тем более делает урлы уродскими и непонятными
/a/b/c/d/e/f/
a=b&c=d&e=f
другое дело, когда реальное ЧПУ
new/first - вот это роут news/{slug}, а /news/read/slug/first - это кусок говна.
news?slug=first - это тоже не айс.
 

keltanas

marty cats
malina95Практика передовать параметры /parameter/value - ужасна, для этого есть GET. сам бользовался, пока не осознал, что в 99% это не нужно, к ЧПУ это никакого отношения не имеет, тем более делает урлы уродскими и непонятными
Тоже на этом обжигался.
 

malina95

Дракула кода:)
Не знаю, вы наверное правы, но такие урлы "ключ -> значение" очень удобные, и как по мне, автомат намного быстрее будет работать, регулярки много памяти гребут. Кстати, вот мой роутер теперь после всех изменений:
PHP:
<?php

	namespace Core;
	
	class FrontController {
		
		private $defaultController = 'IndexController';
        private $defaultAction = 'indexAction';
		
		private $controller = false;
		private $action = false;
		private $args = false;
		
		private function getURI () {
			return trim($_SERVER['REQUEST_URI'], '/');
		}
		
		public function Start () {
			
			// Получаем URI.
			$uri = $this->getURI();
			
			//$uri = substr($uri, 0, mb_strpos($uri, '?'));
			$segments = explode('/', $uri);
        
			// Первый сегмент — контроллер.
			$this->controller = !empty($segments[0]) ? ucfirst($segments[0]).'Controller' : $this->defaultController;
			// Второй — действие.
			$this->action = !empty($segments[1]) ? $segments[1].'Action' : $this->defaultAction;
			// Остальные сегменты — параметры.
			if (isset($segments[2]) && !empty($segments[2])) {
				$keys = $values = array();
				for ($i = 2, $cnt = count($segments); $i < $cnt; $i++) {
					if ($i % 2 == 0)
						$keys[] = $segments[$i];
					else
						$values[] = $segments[$i];
				}
				if ($keys and $values)
					$this->args = array_combine($keys, $values);
			}
			
 
            // Подключаем файл контроллера, если он имеется
			$controllerFile = 'App/Controllers/'.$this->controller.'.php';
			if (file_exists($controllerFile)) {
				include($controllerFile);
				$this->controller = new $this->controller();
			}
			else {
				exit("404 - нужного контроллера нет");
				return;
			}
			
			// Если не загружен нужный класс контроллера или в нём нет
			// нужного метода — 404
			if (is_callable(array($this->controller, $this->action)) === false)
				exit("Если не загружен нужный класс контроллера или в нём нет нужного метода — 404 ");
				
			// Вызываем действие контроллера с параметрами
			if ($this->args !== false) {
				if ($this->controller->$this->action($this->args) === false)
					exit('Не могу запустить в контроллере : '.$this->controller.' метод : '.$this->action.' с параметрами : '.$this->args.'!');
			}
			else
				if (call_user_func(array($this->controller, $this->action)) === false)
					exit('Не могу запустить в контроллере : '.$this->controller.' метод : '.$this->action.'!');
				
		}
		
	}
	
?>
Все exit и ошибки это тестирование, их не будет, везде будут редиректы 404.
И не спрашивайте почему я не использовал call_user_func_array, он не правильно передаёт массив данных методу, тоесть после передачи массив исчезает.
 

radioheaded

PHP нуб

malina95

Дракула кода:)
Чего возмущаешся? Скажи по-русски, анлийский я не знаю, а переводчик отключили)))
 

hell0w0rd

Продвинутый новичок
А почему у тебя контроллер выполняет роль роутера?
 

malina95

Дракула кода:)
Всмысле? FrontController я назвал от фонаря, он запускает все запросы.
 

fixxxer

К.О.
Партнер клуба
называть классы от фонаря - это не самый лучший способ именования =)

а зачем тебе там модели? модели должны инстанциироваться контроллерами, к роутингу они не имеют отношения
 
  • Like
Реакции: WMix

keltanas

marty cats
Вы как будто сами не помните себя в этом возрасте? Пусть человек потратит лучших N лет своей молодости на разработку самого лучшего фреймворка в мире. А потом поймет, как надо было...
 

malina95

Дракула кода:)
Хах, я не трачу лучшие годы на это, лучшие годы я посеял при изучении php, учил 2 года, и только сейчас учу ооп... Если я скину архив посмотрите?
 

keltanas

marty cats
Если я скину архив посмотрите?
А зачем? Все что ты пишешь, ты сейчас пишешь только для себя. Наверняка, у тебя и тестов к этому нет. И обоснования твоего подхода.
Если делаешь для кого-то, лучше взять проверенное и оттестированное решение. Когда поймешь, что можно сделать лучше и почему, тогда можешь попробовать предложить другим.
 

malina95

Дракула кода:)
Ну впринципе да, я делаю для себя, чтобы делать сайты визитки
 

Absinthe

жожо
malina95 зачем тебе столько визиток?
Или ты их другим людям делаешь? Про wordpress знаешь?
 
Сверху