|
<?php |
|
/** |
|
* Базовая логика |
|
*/ |
|
|
|
/** |
|
* Класс исключений при обработке HTTP |
|
*/ |
|
class HttpException extends Exception {} |
|
|
|
/** |
|
* Класс исключений при обработке роутинга - для перехвата ситуаций "Страница/объект не найдены) |
|
*/ |
|
class NotFoundException extends Exception {} |
|
|
|
/** |
|
* Класс обработки входящих запросов |
|
*/ |
|
class HttpRequest |
|
{ |
|
protected $_requestUri; |
|
|
|
public function getRequestUri() |
|
{ |
|
if($this->_requestUri===null) |
|
{ |
|
if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS |
|
$this->_requestUri=$_SERVER['HTTP_X_REWRITE_URL']; |
|
elseif(isset($_SERVER['REQUEST_URI'])) |
|
{ |
|
$this->_requestUri=$_SERVER['REQUEST_URI']; |
|
if(!empty($_SERVER['HTTP_HOST'])) |
|
{ |
|
if(strpos($this->_requestUri,$_SERVER['HTTP_HOST'])!==false) |
|
$this->_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',$this->_requestUri); |
|
} |
|
else |
|
$this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',$this->_requestUri); |
|
} |
|
elseif(isset($_SERVER['ORIG_PATH_INFO'])) // IIS 5.0 CGI |
|
{ |
|
$this->_requestUri=$_SERVER['ORIG_PATH_INFO']; |
|
if(!empty($_SERVER['QUERY_STRING'])) |
|
$this->_requestUri.='?'.$_SERVER['QUERY_STRING']; |
|
} |
|
else |
|
throw new HttpException('HttpRequest is unable to determine the request URI.'); |
|
} |
|
|
|
return $this->_requestUri; |
|
} |
|
} |
|
|
|
/** |
|
* Класс обработки ответов |
|
*/ |
|
class HttpResponse { |
|
|
|
public function send($headers, $content) |
|
{ |
|
|
|
} |
|
} |
|
|
|
/** |
|
* Интерфейс для классов, реализующих сопоставление параметров HTTP запроса и логики |
|
*/ |
|
interface RouterInterface { |
|
|
|
/** |
|
* Выполняет разбор параметров HTTP запроса |
|
* Возвращает false если не смог найти подходящее правило |
|
* @param HttpRequest $request |
|
* @return mixed|false |
|
*/ |
|
public function route($request); |
|
} |
|
|
|
/** |
|
* Класс для блоков-компонент |
|
*/ |
|
class Component |
|
{ |
|
/** |
|
* @var WebApplication |
|
*/ |
|
protected $app; |
|
|
|
protected $config; |
|
|
|
public function __construct(WebApplication $app, $config = []) |
|
{ |
|
$this->app = $app; |
|
$this->config = $config; |
|
} |
|
|
|
public function init() |
|
{ |
|
|
|
} |
|
} |
|
|
|
/** |
|
* Класс компонент типа Модуль |
|
*/ |
|
abstract class Module extends Component |
|
{ |
|
|
|
} |
|
|
|
/** |
|
* Класс компонент типа Диспетчер правил роутинга |
|
*/ |
|
abstract class Dispatcher extends Component |
|
{ |
|
/** |
|
* Метод должен извлечь из $route информацию об исполнимом коде, который должен в итоге сгенерировать ответ на HTTP запрос |
|
* @param $route |
|
* @return mixed |
|
*/ |
|
abstract public function dispatch($route); /** тут расписывать не буду */ |
|
} |
|
|
|
/** |
|
* Класс приложений типа "Веб-приложение" |
|
*/ |
|
class WebApplication |
|
{ |
|
protected $request; |
|
|
|
protected $response; |
|
|
|
protected $config; |
|
|
|
public function __construct($config = []) |
|
{ |
|
$this->request = new HttpRequest; |
|
$this->response = new HttpResponse; |
|
$this->config = $config; |
|
} |
|
|
|
public function init() |
|
{ |
|
// инициализация модулей |
|
if (isset($this->config['module']) && is_array($this->config['module'])) |
|
{ |
|
foreach($this->config['module'] as $config) |
|
$module = $this->getComponent($config); // при этом неявно вызывается module->init; |
|
} |
|
} |
|
|
|
public function run() |
|
{ |
|
// поиск роута с помощью списка роутеров |
|
|
|
if (!isset($this->config['router'])) |
|
throw new NotFoundException('WebApplication is unable to find code to run'); |
|
|
|
$routers = $this->config['router']; |
|
|
|
if (is_string($routers)) |
|
$routers = [ $routers ]; |
|
|
|
foreach($routers as $config) |
|
{ |
|
if (null!== ($router = $this->getComponent($config))) |
|
{ |
|
if ($router instanceof RouterInterface || method_exists($router, 'route')) |
|
{ |
|
$route = $router->route($this->request); |
|
if (false!==$route) |
|
{ |
|
/* Этот блок кода не реализован */ |
|
|
|
/* |
|
$dispatcherConfig = isset($this->config['dispatcher']) ? $this->config['dispatcher'] : []; |
|
if (null!== ($dispatcher = $this->getComponent($dispatcherConfig))) |
|
{ |
|
$dispatcher->dispatch($route); |
|
} |
|
*/ |
|
|
|
/* по окончении блока кода надо завершить цикл поиска роутеров */ |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* Значит либо нет ни одного роутера, либо ни один из них не смог распознать запрос */ |
|
throw new NotFoundException('WebApplication is unable to find code to run'); |
|
} |
|
|
|
/** |
|
* Регистрация дополнительного роутера |
|
* @param $config |
|
*/ |
|
public function registerRouter($config) |
|
{ |
|
if (!isset($this->config['router'])) |
|
$this->config['router'] = []; |
|
|
|
$this->config['router'][] = $config; |
|
} |
|
|
|
/** |
|
* Инициализация класса, реализующего логику компонент |
|
* @param $config |
|
* @return null |
|
*/ |
|
protected function getComponent($config) |
|
{ |
|
$className = null; |
|
if (is_string($config)) |
|
{ |
|
$className = $config; |
|
$config = []; |
|
} elseif(is_array($config)) |
|
{ |
|
if (isset($config['class'])) |
|
{ |
|
$className = $config['class']; |
|
unset($config['class']); |
|
} |
|
} |
|
|
|
if(!is_null($className)) |
|
{ |
|
$component = new $className($this, $config); |
|
if ($component instanceof Component || method_exists($component, 'init')) |
|
$component->init(); |
|
|
|
return $component; |
|
} |
|
|
|
return null; |
|
} |
|
} |