Роутер CMS


Notice: Функция get_currentuserinfo с версии 4.5.0 считается устаревшей! Используйте wp_get_current_user(). in /hlds/web/u138079p19/code4life.ru/htdocs/wp-includes/functions.php on line 3840

Рассмотрев основные моменты понятия CMS в прошлой статье, необходимо рассмотреть такой значимый элемент как роутер CMS или маршрутизатор.

Когда мне понадобилось узнать более подробно что это такое, то к сожалению мне не удалось найти хоть какой-то вменяемой информации, были ссылки на open source проекты … но это мягко говоря не то что надо было, мне нужна была теория)) В данной статье я попытаюсь восполнить это.

Определения

Роутер CMS (маршрутизатор) — это объект CMS управляющий (косвенно) функционалом этой CMS на основе запроса, который вводит пользователь (переход по ссылкам, ввод). В качестве объекта здесь может быть к примеру объект класса.

Вроде понятно. CMS содержит роутер, и он управляет тем возможностями, которые она предоставляет, только роутер может вообще ничего не знать о функционале CMS, потому что роутер управляет посредством контроллеров.

Контроллер — это объект передаваемый роутеру, который содержит логику выполнения определенных действий, в ответ на определенный запрос. В качестве объекта здесь может выступать объект класса, функция и прочее. В своей реализации я использую функции в качестве контроллеров.

То есть, получается, CMS создает роутер, посылает ему все возможные контроллеры, причем каждый контроллер будет вызываться только в случае определенного запроса (либо наиболее подходящего), затем CMS получая запрос отправляет его роутеру и вызывает исполнение роутера, который в свою очередь вызывает соответствующий контроллер (реакция на запрос). И таким образом происходит выполнение логики всех возможностей CMS.

Немного сложно, но на деле все чрезвычайно просто.

Не буду томить, приведу код своей реализации (кстати многие моменты помог сделать Евгений).

Реализация

Для начала я отредактировал .htaccess чтобы получать строку запроса:


AddDefaultCharset utf-8

<IfModule mod_rewrite.c>
RewriteEngine On
Options +FollowSymlinks
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]
</IfModule>

Затем класс роутера CMS:


defined('FILE_PROTECTION') or die('restricted access'); /* Роутер управляет всем поведением посредством обработчиков (контролеров). Для установки поведения необходимо установить нужные элементы адресов и обработчик */ //! возвращает элемент из строки запроса по id 
function RouterGetURLkey($id) 
{ 
	return $GLOBALS["g_oRouter"]->getURLkey($id);
}

//! добавить обработчик 
function RouterAddHandler($aURL, $fnHandler)
{
	$GLOBALS["g_oRouter"]->addHandler($aURL, $fnHandler);
}

//! сшивает между собой (через /) элементы запроса, начиная с нулевого
function RouterGetURLveld($iCount)
{
	return $GLOBALS["g_oRouter"]->getURLveld($iCount);
}

//! возвращает количество совпадений $sURL и переданного урл роутеру, $sURL разбивается как explode("/", $sURL)
function RouterGetCountCmp($sURL)
{
	return $GLOBALS["g_oRouter"]->getCountCmp($sURL);
}

//! обработчик
class CHandler
{
	public $m_aURL;		//!< массив адресов (следующих друг за другом) при котором сработает обработчик
	public $m_fnHadler;	//!< функция обработчик //public function CHandler() {} public function CHandler($aURL, $fnHandler) { $this->m_aURL = $aURL;
		$this->m_fnHadler = $fnHandler;
	}
};

//! класс роутера
class CRouter
{
	private $m_sURLSource;	//!< исходная строка запроса
	private $m_aURL;		//!< распарсенная строка запроса в массив, токен парсинга / (адрес не входит сюда)
	private $m_aHandlers;	//!< массив обработчиков CHandler //! конструктор, на вход обязательна текущая стркоа запроса, как она получается это уже дело не роутера public function CRouter($sURL) { $this->m_sURLSource = $sURL;
		
		//если строка запроса пустая, значит мы на главной
		if(empty($sURL))
		{
			//создаем массив с единственным ключом /
			$this->m_aURL = array("/");
		}
		else
			$this->m_aURL = explode("/", $sURL);
	}
	
	/*! добавить обработчик 
	 \note Для добавления контролера на главную страницу в $aURL необходимо записать array("/")
	*/
	public function addHandler($aURL, $fnHandler)
	{
		$this->m_aHandlers[] = new CHandler($aURL, $fnHandler);
	}
	
	//! возвращает элемент из строки запроса по id
	public function getURLkey($id)
	{
		return $this->m_aURL[$id];
	}
	
	//! сшивает между собой (через /) элементы запроса, начиная с нулевого
	public function getURLveld($iCount)
	{
		$sStr = "";
		if($iCount > count($this->m_aURL))
			$iCount = count($this->m_aURL);

		for($i=0; $i < $iCount; ++$i) { $sStr .= $this->m_aURL[$i] . "/";
		}

		return $sStr;
	}
	
	//! выполнение обработки запроса в соответствии с установленными обработчиками, выполняется наиболее подходящий
	public function execute()
	{
		if(empty($this->m_aHandlers) || count($this->m_aHandlers) == 0)
			return;
		
		$iCountCmp = 0;
		$fnSuitable = null;
		
		foreach($this->m_aHandlers as $oHandler)
		{
			for($i = 0, $il = count($oHandler->m_aURL); $i < $il; ++$i) { if(strcasecmp($oHandler->m_aURL[$i],$this->m_aURL[$i]) == 0)
				{
					//echo $oHandler->m_fnHadler . "";
					if($iCountCmp < $i+1) { $iCountCmp = $i+1; $fnSuitable = $oHandler->m_fnHadler;
					}
				}
				else
					break;
			}
		}
		
		if(isset($fnSuitable))
		{
			$fnSuitable();
		}
		else
		{
			tpl_setVar('content', Get404());
		}
	}
	
	//! возвращает количество совпадений $sURL и переданного урл роутеру, $sURL разбивается как explode("/", $sURL)
	public function getCountCmp($sURL)
	{
		//если анализируемая строка относится к главной странице и массив содержи нулевой ключ / значт мы на главной
		if($sURL == "/" && $this->m_aURL[0] == "/")
			return 1;
			
		$aURL = explode("/", $sURL);
		
		$iCountCmp = 0;
		
		for($i = 0, $il = count($this->m_aURL); $i < $il; ++$i) { if(strcasecmp($this->m_aURL[$i],$aURL[$i]) == 0)
			{
				++$iCountCmp;
			}
			else
				break;
		}
		
		return $iCountCmp;
	}
};

Роутер принимает на вход массив строк, эти строки в запросе должны следовать последовательно и должны быть разделены слэшем /. Все предполагаемые запросы должны быть относительно адреса сайта.

Затем инициализирую роутер CMS (я делаю в index.php):

$g_oRouter = new CRouter($_GET['q']);

Здесь $_GET[‘q’] содержит полный запрос.

После чего передаю все контроллеры роутеру. Пример:

function ControllersFeedback()
{
echo "this is page for feedback";
}

RouterAddHandler(["feedback"], ControllersFeedback);

ControllersFeedback — в данном случае контроллер-функция, которая будет реагировать на запрос «feedback».

А теперь другой запрос:

function ControllersAdminPosts()
{
echo "this is AdminPosts";
}

RouterAddHandler(["admin", "posts"], ControllersAdminPosts);

После того как все контроллеры с запросами переданы, можно запускать роутер CMS на исполнение:

$g_oRouter->execute();

Как видно — все очень просто))

Если надо используйте код на здоровье))

Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*