1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-07-05 07:54:24 +03:00
ifhub.club/engine/classes/Router.class.php

502 lines
15 KiB
PHP
Raw Normal View History

<?php
2008-09-21 09:36:57 +03:00
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
2009-07-26 16:43:16 +03:00
require_once("Action.class.php");
require_once("ActionPlugin.class.php");
2008-09-21 09:36:57 +03:00
/**
* Класс роутинга(контроллера)
* Инициализирует ядро, определяет какой экшен запустить согласно URL'у и запускает его.
*
* @package engine
* @since 1.0
2008-09-21 09:36:57 +03:00
*/
class Router extends LsObject {
/**
* Конфигурация роутинга, получается из конфига
*
* @var array
*/
2008-09-21 09:36:57 +03:00
protected $aConfigRoute=array();
/**
* Текущий экшен
*
* @var string|null
*/
2008-09-21 09:36:57 +03:00
static protected $sAction=null;
/**
* Текущий евент
*
* @var string|null
*/
2008-09-21 09:36:57 +03:00
static protected $sActionEvent=null;
/**
* Имя текущего евента
*
* @var string|null
*/
static protected $sActionEventName=null;
/**
* Класс текущего экшена
*
* @var string|null
*/
2008-09-21 09:36:57 +03:00
static protected $sActionClass=null;
/**
* Текущий полный ЧПУ url
*
* @var string|null
*/
2009-02-23 01:15:08 +02:00
static protected $sPathWebCurrent = null;
/**
* Список параметров ЧПУ url
* <pre>/action/event/param0/param1/../paramN/</pre>
*
* @var array
*/
2008-09-21 09:36:57 +03:00
static protected $aParams=array();
/**
* Объект текущего экшена
*
* @var Action|null
*/
2008-09-21 09:36:57 +03:00
protected $oAction=null;
/**
* Объект ядра
*
* @var Engine|null
*/
protected $oEngine=null;
/**
* Покаывать или нет статистику выполнения
*
* @var bool
*/
static protected $bShowStats=true;
/**
* Объект роутинга
* @see getInstance
*
* @var Router|null
*/
2008-09-21 09:36:57 +03:00
static protected $oInstance=null;
2008-09-21 09:36:57 +03:00
/**
* Делает возможным только один экземпляр этого класса
*
* @return Router
*/
static public function getInstance() {
if (isset(self::$oInstance) and (self::$oInstance instanceof self)) {
return self::$oInstance;
} else {
self::$oInstance= new self();
return self::$oInstance;
}
}
/**
* Загрузка конфига роутинга при создании объекта
*/
2009-07-26 16:43:16 +03:00
protected function __construct() {
$this->LoadConfig();
}
2008-09-21 09:36:57 +03:00
/**
2009-07-26 16:43:16 +03:00
* Запускает весь процесс :)
*
*/
public function Exec() {
$this->ParseUrl();
$this->DefineActionClass(); // Для возможности ДО инициализации модулей определить какой action/event запрошен
$this->oEngine=Engine::getInstance();
$this->oEngine->Init();
$this->ExecAction();
$this->Shutdown(false);
}
/**
* Завершение работы роутинга
*
* @param bool $bExit Принудительно завершить выполнение скрипта
*/
public function Shutdown($bExit=true) {
2009-07-26 16:43:16 +03:00
$this->AssignVars();
$this->oEngine->Shutdown();
$this->Viewer_Display($this->oAction->GetTemplate());
if ($bExit) {
exit();
}
2009-07-26 16:43:16 +03:00
}
/**
* Парсим URL
2008-09-21 09:36:57 +03:00
* Пример: http://site.ru/action/event/param1/param2/ на выходе получим:
* self::$sAction='action';
* self::$sActionEvent='event';
* self::$aParams=array('param1','param2');
*
*/
2009-07-26 16:43:16 +03:00
protected function ParseUrl() {
$sReq = $this->GetRequestUri();
$aRequestUrl=$this->GetRequestArray($sReq);
2010-10-13 15:14:27 +03:00
$aRequestUrl=$this->RewriteRequest($aRequestUrl);
2008-09-21 09:36:57 +03:00
self::$sAction=array_shift($aRequestUrl);
self::$sActionEvent=array_shift($aRequestUrl);
self::$aParams=$aRequestUrl;
}
/**
* Метод выполняет первичную обработку $_SERVER['REQUEST_URI']
*
* @return string
*/
protected function GetRequestUri() {
$sReq=preg_replace("/\/+/",'/',$_SERVER['REQUEST_URI']);
$sReq=preg_replace("/^\/(.*)\/?$/U",'\\1',$sReq);
2010-07-06 15:09:18 +03:00
$sReq=preg_replace("/^(.*)\?.*$/U",'\\1',$sReq);
/**
* Формируем $sPathWebCurrent ДО применения реврайтов
*/
self::$sPathWebCurrent=Config::Get('path.root.web')."/".join('/',$this->GetRequestArray($sReq));
return $sReq;
}
/**
* Возвращает массив реквеста
*
* @param string $sReq Строка реквеста
* @return array
*/
protected function GetRequestArray($sReq) {
2013-04-08 11:50:44 +03:00
$aRequestUrl = ($sReq=='') ? array() : explode('/',trim($sReq,'/'));
for ($i=0;$i<Config::Get('path.offset_request_url');$i++) {
array_shift($aRequestUrl);
}
2010-07-06 15:19:17 +03:00
$aRequestUrl = array_map('urldecode',$aRequestUrl);
return $aRequestUrl;
}
/**
* Применяет к реквесту правила реврайта из конфига Config::Get('router.uri')
*
* @param $aRequestUrl Массив реквеста
* @return array
*/
2010-10-13 15:14:27 +03:00
protected function RewriteRequest($aRequestUrl) {
/**
* Правила Rewrite для REQUEST_URI
*/
$sReq=implode('/',$aRequestUrl);
if($aRewrite=Config::Get('router.uri')) {
$sReq = preg_replace(array_keys($aRewrite), array_values($aRewrite), $sReq);
2010-10-13 15:14:27 +03:00
}
return ($sReq=='') ? array() : explode('/',$sReq);
}
/**
* Выполняет загрузку конфигов роутинга
*
*/
2013-07-10 07:41:47 +03:00
public function LoadConfig() {
//Конфиг роутинга, содержит соответствия URL и классов экшенов
$this->aConfigRoute = Config::Get('router');
// Переписываем конфиг согласно правилу rewrite
foreach ((array)$this->aConfigRoute['rewrite'] as $sPage=>$sRewrite) {
if(isset($this->aConfigRoute['page'][$sPage])) {
$this->aConfigRoute['page'][$sRewrite] = $this->aConfigRoute['page'][$sPage];
unset($this->aConfigRoute['page'][$sPage]);
}
}
}
2008-09-21 09:36:57 +03:00
/**
* Загружает в шаблонизатор Smarty необходимые переменные
*
*/
2009-07-26 16:43:16 +03:00
protected function AssignVars() {
$this->Viewer_Assign('sAction',$this->Standart(self::$sAction));
2008-09-21 09:36:57 +03:00
$this->Viewer_Assign('sEvent',self::$sActionEvent);
$this->Viewer_Assign('aParams',self::$aParams);
2013-02-06 07:54:54 +02:00
$this->Viewer_Assign('PATH_WEB_CURRENT',$this->Tools_Urlspecialchars(self::$sPathWebCurrent));
2008-09-21 09:36:57 +03:00
}
/**
* Запускает на выполнение экшен
* Может запускаться рекурсивно если в одном экшене стоит переадресация на другой
*
*/
public function ExecAction() {
$this->DefineActionClass();
/**
* Сначала запускаем инициализирующий евент
*/
$this->Hook_Run('init_action');
$sActionClass=$this->DefineActionClass();
/**
* Определяем наличие делегата экшена
*/
if($aChain=$this->Plugin_GetDelegationChain('action',$sActionClass)) {
if(!empty($aChain)) {
$sActionClass=$aChain[0];
}
}
self::$sActionClass = $sActionClass;
/**
* Если класс экешна начинается с Plugin*_, значит необходимо загрузить объект из указанного плагина
*/
if(!preg_match('/^Plugin([\w]+)_Action([\w]+)$/i',$sActionClass,$aMatches)) {
require_once(Config::Get('path.root.server').'/classes/actions/'.$sActionClass.'.class.php');
} else {
2013-05-12 05:35:07 +03:00
require_once(Config::Get('path.root.server').'/plugins/'.func_underscore($aMatches[1]).'/classes/actions/Action'.ucfirst($aMatches[2]).'.class.php');
}
$sClassName=$sActionClass;
$this->oAction=new $sClassName($this->oEngine,self::$sAction);
2010-02-06 11:04:36 +02:00
/**
* Инициализируем экшен
*/
$this->Hook_Run("action_init_".strtolower($sActionClass)."_before");
$sInitResult = $this->oAction->Init();
$this->Hook_Run("action_init_".strtolower($sActionClass)."_after");
2010-02-06 11:04:36 +02:00
if ($sInitResult==='next') {
2008-09-21 09:36:57 +03:00
$this->ExecAction();
} else {
/**
* Замеряем время работы action`а
*/
$oProfiler=ProfilerSimple::getInstance();
$iTimeId=$oProfiler->Start('ExecAction',self::$sAction);
2010-02-06 11:04:36 +02:00
$res=$this->oAction->ExecEvent();
self::$sActionEventName=$this->oAction->GetCurrentEventName();
$this->Hook_Run("action_shutdown_".strtolower($sActionClass)."_before");
$this->oAction->EventShutdown();
2010-02-06 11:04:36 +02:00
$this->Hook_Run("action_shutdown_".strtolower($sActionClass)."_after");
$oProfiler->Stop($iTimeId);
2010-02-06 11:04:36 +02:00
2008-09-21 09:36:57 +03:00
if ($res==='next') {
$this->ExecAction();
}
}
}
/**
* Определяет какой класс соответствует текущему экшену
*
* @return string
*/
protected function DefineActionClass() {
2008-09-21 09:36:57 +03:00
if (isset($this->aConfigRoute['page'][self::$sAction])) {
2008-09-21 09:36:57 +03:00
} elseif (self::$sAction===null) {
self::$sAction=$this->aConfigRoute['config']['action_default'];
2008-09-21 09:36:57 +03:00
} else {
//Если не находим нужного класса то отправляем на страницу ошибки
self::$sAction=$this->aConfigRoute['config']['action_not_found'];
self::$sActionEvent='404';
2008-09-21 09:36:57 +03:00
}
self::$sActionClass=$this->aConfigRoute['page'][self::$sAction];
return self::$sActionClass;
}
/**
* Функция переадресации на другой экшен
* Если ею завершить евент в экшене то запуститься новый экшен
* Пример: <pre>return Router::Action('error');</pre>
2008-09-21 09:36:57 +03:00
*
* @param string $sAction Экшен
* @param string $sEvent Евент
* @param array $aParams Список параметров
2008-09-21 09:36:57 +03:00
* @return 'next'
*/
static public function Action($sAction,$sEvent=null,$aParams=null) {
self::$sAction=self::getInstance()->Rewrite($sAction);
self::$sActionEvent=$sEvent;
2008-09-21 09:36:57 +03:00
if (is_array($aParams)) {
self::$aParams=$aParams;
}
return 'next';
}
2009-02-23 01:15:08 +02:00
/**
* Возвращает текущий ЧПУ url
2009-02-23 01:15:08 +02:00
*
* @return string
*/
static public function GetPathWebCurrent() {
return self::$sPathWebCurrent;
2009-02-23 01:15:08 +02:00
}
2008-09-21 09:36:57 +03:00
/**
* Возвращает текущий экшен
2008-09-21 09:36:57 +03:00
*
* @return string
*/
static public function GetAction() {
return self::getInstance()->Standart(self::$sAction);
2008-09-21 09:36:57 +03:00
}
/**
* Возвращает текущий евент
2008-09-21 09:36:57 +03:00
*
* @return string
*/
static public function GetActionEvent() {
return self::$sActionEvent;
2008-09-21 09:36:57 +03:00
}
/**
* Возвращает имя текущего евента
*
* @return string
*/
static public function GetActionEventName() {
return self::$sActionEventName;
}
2008-09-21 09:36:57 +03:00
/**
* Возвращает класс текущего экшена
2008-09-21 09:36:57 +03:00
*
* @return string
*/
static public function GetActionClass() {
return self::$sActionClass;
2008-09-21 09:36:57 +03:00
}
/**
* Устанавливает новый текущий евент
2008-09-21 09:36:57 +03:00
*
* @param string $sEvent Евент
2008-09-21 09:36:57 +03:00
*/
static public function SetActionEvent($sEvent) {
self::$sActionEvent=$sEvent;
}
2008-09-21 09:36:57 +03:00
/**
* Возвращает параметры(те которые передаются в URL)
2008-09-21 09:36:57 +03:00
*
* @return array
*/
static public function GetParams() {
return self::$aParams;
}
/**
* Возвращает параметр по номеру, если его нет то возвращается null
* Нумерация параметров начинается нуля
2008-09-21 09:36:57 +03:00
*
* @param int $iOffset
* @param mixed|null $def
2008-09-21 09:36:57 +03:00
* @return string
*/
2009-07-26 16:43:16 +03:00
static public function GetParam($iOffset,$def=null) {
2008-09-21 09:36:57 +03:00
$iOffset=(int)$iOffset;
2009-07-26 16:43:16 +03:00
return isset(self::$aParams[$iOffset]) ? self::$aParams[$iOffset] : $def;
2008-09-21 09:36:57 +03:00
}
/**
* Устанавливает значение параметра
2008-09-21 09:36:57 +03:00
*
* @param int $iOffset Номер параметра, по идеи может быть не только числом
* @param mixed $value
2008-09-21 09:36:57 +03:00
*/
static public function SetParam($iOffset,$value) {
2008-09-21 09:36:57 +03:00
self::$aParams[$iOffset]=$value;
}
/**
* Показывать или нет статистику выполение скрипта
* Иногда бывает необходимо отключить показ, например, при выводе RSS ленты
*
* @param bool $bState
*/
static public function SetIsShowStats($bState) {
self::$bShowStats=$bState;
}
/**
* Возвращает статус показывать или нет статистику
*
* @return bool
*/
static public function GetIsShowStats() {
return self::$bShowStats;
}
/**
* Проверяет запрос послан как ajax или нет
*
* @return bool
*/
static public function GetIsAjaxRequest() {
return isAjaxRequest();
}
2008-09-21 09:36:57 +03:00
/**
* Ставим хук на вызов неизвестного метода и считаем что хотели вызвать метод какого либо модуля
* @see Engine::_CallModule
2008-09-21 09:36:57 +03:00
*
* @param string $sName Имя метода
* @param array $aArgs Аргументы
* @return mixed
2008-09-21 09:36:57 +03:00
*/
public function __call($sName,$aArgs) {
return $this->oEngine->_CallModule($sName,$aArgs);
}
/**
* Блокируем копирование/клонирование объекта роутинга
*
*/
protected function __clone() {
}
/**
* Возвращает правильную адресацию по переданому названию страницы(экшену)
*
* @param string $action Экшен
* @return string
*/
2009-08-19 13:47:19 +03:00
static public function GetPath($action) {
// Если пользователь запросил action по умолчанию
$sPage = ($action == 'default')
? self::getInstance()->aConfigRoute['config']['action_default']
: $action;
// Смотрим, есть ли правило rewrite
$sPage = self::getInstance()->Rewrite($sPage);
return rtrim(Config::Get('path.root.web'),'/')."/$sPage/";
}
/**
* Try to find rewrite rule for given page.
* On success return rigth page, else return given param.
*
* @param string $sPage
* @return string
*/
public function Rewrite($sPage) {
return (isset($this->aConfigRoute['rewrite'][$sPage]))
? $this->aConfigRoute['rewrite'][$sPage]
: $sPage;
}
/**
* Стандартизирует определение внутренних ресурсов.
*
* Пытается по переданому экшену найти rewrite rule и
* вернуть стандартное название ресусрса.
*
* @see Rewrite
* @param string $sPage
* @return string
*/
public function Standart($sPage) {
$aRewrite=array_flip($this->aConfigRoute['rewrite']);
return (isset($aRewrite[$sPage]))
? $aRewrite[$sPage]
: $sPage;
}
/**
* Выполняет редирект, предварительно завершая работу Engine
*
* @param string $sLocation URL для редиректа
*/
static public function Location($sLocation) {
self::getInstance()->oEngine->Shutdown();
func_header_location($sLocation);
}
2008-09-21 09:36:57 +03:00
}
?>