MaxSite CMS. Схема/описание работы
12-01-2008Reading time ~ 5 min.PHP 48624
Попробую как-то обрисовать свои идеи. Постепенно я прихожу к более ясному пониманию того, чего хотелось бы увидеть в CMS; что в ней будет самым главным.
Основной момент, хотя я об этом уже говорил,- это не выполнять никаких действий то того, как они действительно понадобятся.
Возьмем для примера WordPress. При получении запроса, «движок» выполняет инициализацию, обращается к БД и заносит полученные данные в переменные. После этого включается шаблон и уже в нем выполняется обход полученных данных в цикле. То есть, если мне нужны какие-то другие данные для этой страницы или нужно учесть другие условия, то я должен буду заново сформировать запрос к БД и получить новую порцию данных.
Но, поскольку в WordPress'е все довольно серьезно переплетено, то возникнет масса нюансов, которые следует обязательно учитывать: например тип страницы изменится или пагинация собъётся.
Возьмем другой пример: система, которая работает по принципу «Модель-Контролер-Представление» (MVC). Считается, что данные должны получаться в контролере и передаваться для отображения в «Представлении» (view). Так вот загвоздка здесь в том, что вывод зависит от множества параметров. Если наша система будет поддерживать шаблоны, то как именно отображать и что именно будет определяться уже в шаблоне. То есть на самом последнем уровне. Это конечно несколько выходит за границы теории, но такова практика.
Вот вполне реальный пример. Предположим, идет запрос на отображение рубрики. Теоретически мы можем в контролере выполнить запрос к БД и получить все данные. После этого передать их в шаблон и там вывести. Но мы знаем, что разные шаблоны могут по разному выводить данные. Прежде всего это определяется желанием заказчика. Многим нравятся рубрики в виде заголовка и даты, другим нужно выводить немного текста/анонса заметки, а третьи хотят получить полнотекстовый «блоговский» вывод.
То есть в первом случае нам нужно всего лишь получить заголовки и дату, а в других нужно получить и тексты. При этом мы получаем еще массу условий - например нужен ли автор записи? Или количество комментариев?..
Мы видим, что условие, по которому нужно осуществить выборку из БД определяется аж в самом хвосте цепочки. Из-за всего этого, работу системы я вижу примерно так:
Теперь небольшое описание.
1. Входящий адрес принимает CodeIgniter. Он сам определяет что с ним делать. Но настраиваем его мы так, чтобы все запросы автоматом передавались нашему контролеру.
2. Наш контролер, благодаря CodeIgniter, сразу вполняет функции типа. Например если в адресе указывается «archive», значит будет выполняться функция «archive» (с таким же названием). При этом у нас в конструкторе сразу подключается библиотека основных функций CMS, а также считываются основные настройки. (Пока они сделаны в виде файла, но должны храниться в БД.) Здесь же происходит интересная вещь: если указывается несуществующая функция (тип), то стандартно CodeIgniter выдает сообщение об ошибке (404). Нас это не устраивает, поэтому я немного изменил CodeIgniter и теперь управление передается не на страницу ошибки, а на функцию контролера page_404(). И если этой функции нет, то уже на стандартную 404-страницу. Таким образом мы можем подключить свой обработчик несуществующих типов.
Но это еще не все. Если нам нужно подключить свой тип страницы, то не обязательно переписывать контролер. Вместо этого контролер сам проверяет существование php-файла с именем входящего типа. И если есть, то подключаем как обычно через require(). Если же нет, то передаем управление на главную страницу (функция home()).
Таким образом, если возникнет необходимость расширить типы данных, то делается это очень просто: создается php-файл с именем типа и в нем несколько строк, где указывается тип и вьвер - все данные автоматом передадутся по цепочке в файл шаблона.
3. В контролере заполняется специальная структура-массив, где указывается тип страницы. Так же здесь передается входящий url и его сегменты. В общем эта информация нам нужна для того, чтобы в самом шаблоне можно было бы сразу получить файл типа страницы.
4. После контролера управление передается на вьювер (view). Поскольку у нас уже есть своя структура с нужными для шаблона данными, то мы используем один-единственный вьювер. В нем мы передаем наши переменные и смотрим текущий шаблон. Шаблон указывается в конфигурации и совпадает с каталогом. По-умолчанию используется шаблон «default».
Правда здесь стоит сделать отдельное замечание. Поскольку мы сразу же предполагаем, что у нас будет использваться RSS, то мы будем анализировать входящий адрес на наличие «feed» в конце. И если таково имеется, то управление будем передавать на другой вьювер - «feed».
5. В отличие от WordPress, управление в наш шаблон всегда передается в файл index.php. Всегда. В нем выполняется селектор типа страницы (тот который мы получили в начале). Выглядит это примерно так:
if ( is_type('archive') ) require('archive.php'); elseif ( is_type('author') ) require('author.php'); elseif ( is_type('category') ) require('category.php'); elseif ( is_type('home') ) require('home.php'); elseif ( is_type('link') ) require('link.php'); elseif ( is_type('page') ) require('page.php'); elseif ( is_type('page_404') ) require('page_404.php'); elseif ( is_type('search') ) require('search.php'); elseif ( is_type('tag') ) require('tag.php'); else require('page_404.php');
Как видите это примерно тоже, что и вордпрессовские is_home, is_archive и т.п., только сделано как одна универсальная функция. При этом тип у нас определяется однозначно, а не так как в WordPress, когда рубрика может быть и архивом.
В зависимости от типа мы подключаем нужные нам файлы. При этом имена могут быть произвольными.
6. Уже в этом подключаемом файле мы и будем выполнять запросы к БД (точнее это будет набор готовых функций), заполнять начальные сведения для header страницы и после этого выполняем нужный нам вывод (типа TheLoop).
Вот пример home.php:
<?php # подготовка данных $MSO->title = 'Главная страница сайта'; $MSO->keywords = 'Ключевики'; $MSO->description = 'Описание сайта для этой страницы'; # получение данных ... # начало вывода # подключается header и начало html-дизайна require('main-start.php'); ?> Home - все что угодно - сам вывод данных <?php # завершение html, footer и т.п. require('main-end.php'); ?>
Хочу сказать, что такая схема (в принципе) если оставить конфигурацию в отдельном файле способна без проблем работать вообще без использования БД. Например если данные хранятся в текстовых файлах. ;)
Если же мы будем использвать БД, то до передачи управления файлу шаблона, мы выполним (теоретически) единственный запрос к БД, чтобы получить конфигурацию файла.
Не знаю, есть ли такое в PHP, но в питоновском Джанго все данные из БД вытаскиваются с помощью "ленивых" (lazy) объектов QuerySet (впрочем, неважно, как они называются). Такой объект накапливает информацию о фильтрах данных, сортировке и т.п., но сам запрос делается только тогда, когда мы пытаемся обратиться к данным. Например, мы можем отфильтровать данные, задать сортировку, выбрать slice от 10го по 20 элемент, и только когда попробуем по результату итерироваться циклом (обычно это уже в шаблоне делается) - делается запрос к БД, причем только для нужных данных.
Определять же столбцы для запроса "на лету", по-моему, нет особого смысла. Если таблица не очень "широкая", то сервер БД одинаково быстро будет доставать и два столбца, и 10 - скорее, все упрется в скорость фильтрации. Т.е. проще и столь же эффективно получтся, если достать всю запись, а потом уже в шаблоне выводить нужные поля.
Еще меня смущает вынос header и footer в отдельные php-файлы... CodeIgniter не поддерживает наследование шаблонов (вроде такого: http://www.djangoproject.com/documentation/templates/#template-inheritance) ?
Понятно, спасибо.
В CodeIgniter есть нечто подобное: можно с помощью специальных функций создать запрос в виде
<br>$this->db->select('title, content, date');<br>$this->db->from('mytable');<br>
Соответственно потом его где-нибудь выполнить. Тут вопрос скорее будет в том, чтобы вынести некоторые условия запроса в конфигурацию/админку, чтобы можно было менять конечный вывод. Но пока я еще не думал над этим.
Шаблон как раз совсем простой получается и можно вообще обойтись одним index.php. Но для вебмастера всё-таки удобней отделить header в отдельный файл, чтобы он не мешал в остальном дизайне.
смахивает на сам вордпресс ))
Сервер mysql клинит не количестве полей, и даже не на количестве выводимых записей, а на сортировке.
Проходящему Гостю: было бы странно, если бы Макс придумывал нечто, смахивающее на Джумлу. :)
Интересно пишешь...как скоро мы увидим твоё творение ?)
Если система может работать и без БД, то какой смысл организовывать БД?
А вообще статья интересная и познавательная. Присоединяюсь к остальным в желании скоро увидеть творение автора.
Может быть тебе поможет схема предложенная Д.Котеровым - его шаблонизатор, все данные накапливаются(или меняются) до файла шаблона, который вызывается в последнюю очередь одним файлом