Доброго всем времени суток. Сегодня мы продолжаем собирать ядро CMS RS-MINI. У нас по плану реализация схемы проектирования MVC, а точнее одной из составляющих этой схемы — контроллеры. Само собой сегодня мы не получим готовую реализацию контроллеров. В нашу задачу на сегодня это написать базу, которая будет наследоваться в будущем.
Что будет входить в базовый класса всех контроллеров в системе? Ну я бы поделил методы класса на два типа
В обязательные будут входить те методы, которые будут вызваться при сборке этих самых контроллеров (сборка будет происходить в классе application.class.php) в системе. Так же те, которые позволяют получить данные назначенные в этой самой сборке.
В категорию «не очень обязательных» я включаю те методы которые будут лишь помогать при написание контроллеров для модулей (эдакий инструментарий)
Да вот еще что, все методы из необязательной категории появились в результате практики. Если бы я сейчас писал систему не имея в этом опыта, скорее всего класс состоял бы только из обязательных методов.
Давайте перечислю эти методы и зачем они нам понадобятся
Методы getCaption(), validate() и run() подвержены полиморфизму. То есть эти методы для использования необходимо будет переназначить в дочернем классе. Если метод validate() или run() вернет false, то система выведет сообщение о 404-ой ошибке. Как Вы могли заметить (если уже смотрели код класса) у метода run() по умолчанию возвращается false, что говорит о том, что этот метод обязательно должен будет переназначен в дочернем классе.
Методы этой категории не обязательны, их вполне можно было реализовать в дочернем коде. Но так как в практике довольно часто приходилось использовать одно и тоже, было решено вынести их (эти методы) в базовую часть.
К таким методам относятся:
Как я и говорил, эти методы не так уж и важны, просто немного упрощают жизнь разработчику.
Прежде чем я выложу код этого класса, хочу пояснить, что этот класс является абстрактным. Абстрактный класса отличаются от обычных только тем, что у программиста нет возможности поднять объект такого класса.
А теперь собственно код класса. (Я его очень хорошо за комментировал, так что все что написано выше можно и не читать ) (файл называется abstractcontroller.class.php и лежит в папке /rs-mini/core/)
<?php
/*
* @package RS-MINI
* @copyright (c) 2015 Alexey Glumov aka Rio-Shaman (support@rio-shaman.ru)
* @license GNU General Public License version 2; see LICENSE.txt
*
*/
namespace core;
if(!defined('RS-MINI')) die();
/*
* abstractcontroller v 1.0
*
* абстрактный класс для контроллеров
*
*/
abstract class abstractcontroller
{
/*
* объект дома
*
* @var - object
* @access - protected
*/
protected $dom;
/*
* объект класса по работе с внешними глобальными переменнами
*
* @var - object
* @access - protected
*/
protected $request;
/*
* массив хранящий значения динамичных страниц
*
* @var - array
* @access - private
*/
private static $dynamicValue;
/*
* массив хранящий параметры контроллера
*
* @var - array
* @access - private
*/
private $paramList;
/*
* контсруктор
* обратите внимания, что объекты класса (dom и request) по умолчанию
* передаются по ссылке что гарантирует нам использование одного и
* того же экземпляра класса (по всему проекту будет существовать одна
* копия объекта)
*
* @access - public
*
* @param object dom - объект класса dom
* @param object request - объект класса request
* @param array paramList - массив с параметрами контроллера
*/
public function __construct($dom, $request, $paramList = array())
{
$this->dom = $dom;
$this->request = $request;
$this->paramList = $paramList;
}
/*
* метод возвращает заголовок страницы
*
* @access - public
*
* @param string caption - системный заголовок
*/
public function getCaption($caption)
{
return $caption;
}
/*
* метод позволит проверить некоторые данные на валидацию.
* запускается для каждого контроллера (за исключением отключенных)
*
* @access - public
* @return - true или false (404 ошибка)
*
*/
public function validate()
{
return TRUE;
}
/*
* запуск контроллера. основной метод контроллера.
* если не создать подобный метод (полиморфизм) в дочернем классе
* контроллер выдаст 404-ую ошибку
*
* @access - public
* @return - true или false (404 ошибка)
*
*/
public function run()
{
return FALSE;
}
/*
* метод запоминает значение динамичной страницы.
* отрабатывает при сборке контроллеров в приложении
* системы. необходим, что бы псевдоним динамической страницы
* можно было получить из любого подключенного контроллера
*
* @access - public
* @return - значение дин страницы
*
* @param string name - имя параметра
*/
public function setDynamicValue($name, $value)
{
self::$dynamicValue[$name] = $value;
}
/*
* метод получает значение динамичной страницы по имени
*
* @access - protected
* @return - значение дин страницы
*
* @param string name - имя параметра
*/
protected function getDynamicValue($name)
{
return (isset(self::$dynamicValue[$name])) ? self::$dynamicValue[$name] : NULL;
}
/*
* метод получает значение параметра по имени.
* если значение содержит запятые, то оно (значение) вернется не
* в виде строки, а в виде массива
*
* @access - protected
* @return - значение параметра
*
* @param string name - имя параметра
*/
protected function getParam($name)
{
if (!isset($this->paramList[$name]))
return NULL;
if (!preg_match('/[\,]+/', $this->paramList[$name]))
return $this->paramList[$name];
$params = explode(',', $this->paramList[$name]);
foreach ($params as $key => $param)
$params[$key] = trim($param);
return $params;
}
/*
* метод редиректит к опрделенному адресу
*
* @access - protected
*
* @param string link - адрес редиректа
*/
protected function redirect($link)
{
header('location: ' . $link);
die();
}
/*
* метод получает сейчашнию дату в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС
*
* @access - protected
*
*/
protected function getNowDate()
{
return date('Y-m-d H:i:s');
}
/*
* метод конвертирует дату из формата ГГГГ-ММ-ДД ЧЧ:ММ:СС в формат ДД Месяц ГГГГ г. ЧЧ:ММ
*
* @access - protected
*
* @param string cdate - дата и время в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС (или ГГГГ-ММ-ДД)
*/
protected function changeDate($cdate)
{
// массив с месяцами по русски
$arrayMonth = array (
'01' => 'Января',
'02' => 'Февраля',
'03' => 'Марта',
'04' => 'Апреля',
'05' => 'Мая',
'06' => 'Июня',
'07' => 'Июля',
'08' => 'Августа',
'09' => 'Сентября',
'10' => 'Октября',
'11' => 'Ноября',
'12' => 'Декабря'
);
// если прислано значение ГГГГ-ММ-ДД ЧЧ:ММ:СС
if ($this->validateDateTime($cdate)) {
// бьем ГГГГ-ММ-ДД ЧЧ:ММ:СС на ГГГГ-ММ-ДД и ЧЧ:ММ:СС
$dateArray = explode(" ", $cdate);
// бьем ГГГГ-ММ-ДД на ГГГГ, ММ и ДД
$dateArray = explode("-", $dateArray[0]);
// бьем ГГГГ-ММ-ДД ЧЧ:ММ:СС на ГГГГ-ММ-ДД и ЧЧ:ММ:СС
$timeArray = explode(" ", $cdate);
// бьем ЧЧ:ММ:СС на ЧЧ, ММ и СС
$timeArray = explode(":", $timeArray[1]);
}
// если прислано значение ГГГГ-ММ-ДД
else
// бьем ГГГГ-ММ-ДД на ГГГГ, ММ и ДД
$dateArray = explode("-", $cdate);
// формируем строку ДД Месяц ГГГГ г. ЧЧ:ММ или ДД Месяц ГГГГ г.
return ""
. $dateArray[2]
. " "
. $arrayMonth[$dateArray[1]]
. " "
. $dateArray[0]
. " г."
. ( ($this->validateDateTime($cdate)) ? " " . $timeArray[0] . ":" . $timeArray[1] : "")
;
}
/*
* метод переводит кириллицу в латинец
*
* @access - protected
*
* @param string string - строка для изменения
*/
protected function getTranslit($string)
{
// массив с символами которые нужно заменить
$what = array(
"а","А","б","Б","в","В","г","Г","д","Д","е","Е","ё","Ё","ж","Ж","з","З",
"и","И","й","Й","к","К","л","Л","м","М","н","Н","о","О","п","П","р","Р",
"с","С","т","Т","у","У","ф","Ф","х","Х","ц","Ц","ч","Ч","ш","Ш","щ","Щ",
"ы","Ы","э","Э","ю","Ю","я","Я","a","A","b","B","c","C","d","D","e","E",
"f","F","g","G","h","H","i","I","j","J","k","K","l","L","m","M","n","N",
"o","O","p","P","q","Q","r","R","s","S","t","T","u","U","v","V","w","W",
"x","X","y","Y","z","Z","1","2","3","4","5","6","7","8","9","0","-"," ",
".","_"
);
// массив с символами на которые нужно заменить
$forWhat = array(
"a","a","b","b","v","v","g","g","d","d","e","e","jo","jo","zh","zh","z","z",
"i","i","j","j","k","k","l","l","m","m","n","n","o","o","p","p","r","r",
"s","s","t","t","u","u","f","f","h","h","c","c","ch","ch","sh","sh","shh","shh",
"y","y","je","je","ju","ju","ja","ja","a","a","b","b","c","c","d","d","e","e",
"f","f","g","g","h","h","i","i","j","j","k","k","l","l","m","m","n","n",
"o","o","p","p","q","q","r","r","s","s","t","t","u","u","v","v","w","w",
"x","x","y","y","z","z","1","2","3","4","5","6","7","8","9","0","-","-",
"-","-"
);
// подгатавливаем паттерн из допустимых символов (массив $what)
$pattern = '/[^' . preg_quote(implode('', $what)) . ']/su';
// заменяем найденые в массиве $what символы в строке string и заменяем на символы из $forWhat
// при этом строка string чистится от всех символов кроме букв (за исключением знаков ь и ъ),
// цифр, точек, тире, нижних подчеркиваний и пробелов (пробелы по краям строки string тоже удаляются)
return str_replace($what, $forWhat, preg_replace($pattern, '', trim($string)));
}
/*
* метод получает телефон в междунородном формате
*
* @access - protected
* @return - телефон в формате 8 (123) 456-78-90
*
* @param string phone - телефон
*/
protected function getPhoneByFormat($phone)
{
// чистим от всего что НЕ число
$phone = preg_replace('/[^0-9]/is', '', $phone);
// если первая цифра 8 или 7, то удаляем ее
$phone = preg_replace('/^(8|7)/is', '', $phone);
// формируем телефон в формате 8 (123) 456-78-90
$phone = ''
. '8'
. ' ('
. $phone[0]
. $phone[1]
. $phone[2]
. ') '
. $phone[3]
. $phone[4]
. $phone[5]
. '-'
. $phone[6]
. $phone[7]
. '-'
. $phone[8]
. $phone[9]
;
return $phone;
}
/*
* метод по урлам определяет выбранный пункт
*
* @access - protected
* @return - true или false
*
* @param string uri - путь до документа
*/
protected function getCurrent($uri)
{
// получаем урл страницы
$openUri = $this->request->getHttpServer('REQUEST_URI')->toUri();
// получаем массив из присланного урла
$openUri = explode('/', $openUri); // бьем строку на массив
if (empty($openUri[(count($openUri) - 1)])) // если последний элемент массива пуст, удаляем его
unset($openUri[(count($openUri) - 1)]);
foreach ($openUri as $key => $alias) // чистим алиасы от пробелов
$openUri[$key] = trim($alias);
// обрабатываем присланный урл
$uri = explode('/', $uri); // бьем строку на массив
if (empty($uri[(count($uri) - 1)])) // если последний элемент массива пуст, удаляем его
unset($uri[(count($uri) - 1)]);
foreach ($uri as $key => $alias) // чистим алиасы от пробелов
$uri[$key] = trim($alias);
$current = TRUE;
// листаем псевдонимы присланного пути
// пример. предположим мы находимся вот по такому пути /about/contact/ (переменная openUri)
// а для проверки прислали вот такой путь /about/ (переменная uri). на глаз можно сказать,
// что мы находимся разделе /about/, т.е. результат метода должен быть TRUE
foreach ($uri as $key => $alias)
// при первой итерации в переменной alias будет значение about
// а в массиве $openUri[0] (ноль потому-что первая итерации, key равен нулю)
// тоже значение about. стало быть условие не выполнится и в переменной current
// так и останится с значением TRUE
// второй итерации не будет, так как в переменной uri был только один элемент массива
// в результате чего метод вернет TRUE как и предпологалось
if (!isset($openUri[$key]) || $openUri[$key] != $alias)
$current = FALSE;
return $current;
}
}
Слов много а дела пока никакого, но это пока. Придет время и Вы увидите как это все работает в связке, а пока нам приходится делать лишь базовые вещи.
Если у Вас есть какие либо вопросы, то задавайте их в комментариях. Результат работ, Вы как всегда можете скачать в конце статьи.
Всего Вам наилучшего, на сегодня все!
Я очень рекомендую автору взглянуть на любой фреймворк (Kohana, Symfony 2)
Есть такие классы как Request, Response, Controller - логика распределена.
Есть хелперы (специально для чего-то вроде getTranslit..)
Удачи)