Книга для разработчиков

Введение

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

В отличии от многих других CMS, использующих различные паттерны типа MVC (Model View Controller), Coffee CMS написана в процедурном стиле, без использования ООП (Объектно-Ориентированного Программирования) и это так и задумано. Чтобы для разработки под нее не требовалось изучать множество разных концепций. Чтобы код был минималистичным, а не разбросанным по тысячам файлов.

Взаимодействие модулей происходит через изменение глобальной переменной $cms. Да, это поругиваемый подход, но он позволяет сильно изменять поведение CMS без изменения кода ядра.

Существует много концепций и паттернов призванных ускорить и упростить доработки CMS, но они хороши для самих разработчиков CMS и плохи для тех кто такую CMS сопровождает. Coffee CMS в первую очередь пытается упростить жизнь сопровождающим. Именно поэтому в ней используются "плохие" практики. Если у вас возникнут предложения по улучшениям, но в рамках именно такого подхода, то оставляйте комментарии на сайте или пишите по любым другим каналам связи указанным на странице поддержки.

Основы работы - Хуки

Вся работа движка Coffee CMS крутится вокруг одного глобального ассоциативного массива $cms.

В нем содержится цепочка хуков в $cms["hooks"]. Хук это некое событие к которому модули прикрепляют свои функции.

Основных событий четыре:

Когда событие происходит, то все функции, прикрепленные к нему, поочередно вызываются. Когда все функции выполнятся, осуществляется переход к следующему хуку, записанному в $cms["hooks"]["query"]["next"]. Т.е. все хуки связаны в цепочку. Это позволяет определять логику поведения CMS, менять ее на лету и отключать ненужные хуки путем установки $cms["hooks"]["query"]["disabled"] = true; что вызовет пропуск хука и переход к следующему. Когда встретится пустой next CMS завершит свою работу.

Функциям при прикреплении можно задавать приоритет выполнения. По умолчанию он равен 10. Чем меньше число, тем раньше выполнится функция. Прикрепленная функция выглядит так:

$cms["hooks"]["query"][5]["cms_base_connect"] = true;

Отдельные функции можно отключать на лету, устанавливая в false.

Кроме того любая функция может сама инициировать запус хука вызовом функции do_hook( "hook_name" );. Так, например, делает модуль карты сайта, давая возможность другим модулям добавить в карту сайта свои ссылки.

Основы работы - Роутинг (Маршрутизация)

Термин "маршрутизация" в контексте веб-программирования и CMS происходит от аналогии с маршрутизаторами (routers) в сетевых технологиях, где пакеты данных направляются к нужным получателям в зависимости от адресов.

Можно ли применять этот термин к Coffee CMS, вопрос пока открытый. Ведь все модули загружаются вне зависимости от URL поступившего запроса и любой из модулей может захотеть его обработать.

В зависимости от URL запроса, CMS должна вести себя по разному. Модули могут добавлять в $cms["urls"] регулярные выражения для сопоставления с URL вида /part1/part2 (без указания протокола и домена, но с полным путем от корня сайта) и хук, который должен запуститься. Например так:

$cms["urls"]["^/admin_url$"] = "admin";
$cms["hooks"]["admin"]["next"] = "template";
$cms["urls"]["^/api_url$"] = "api";
$cms["urls"]["^/cron_url$"] = "cron";

Это дополнительные три хука в Coffee CMS, для функционирования админки, выполнения ajax-запросов на сохранение настроек и текстов страниц, и выполнения периодических задач по таймеру.

Coffee CMS может быть установлена не в корневую папку, а в любую из подпапок и казалось бы излишне добавлять ведущий слеш /. Но это добавляет гибкости, можно с помощью CMS обрабатывать запросы /search, находясь в папке /cms/.

Настройки CMS

Все настройки хранятся в файле .cms/config.php который создается при установке. Этот файл содержит экспортированную переменную $cms["config"] при помощи функции var_export(). Настройки каждого модуля хранятся в отдельном подмассиве с именем этого модуля. Такой подход, всмысле использование php-файла, позволяет быстро их загружать, независимо от наличия соединения с базой данных, а так же избавляет от необходимости писать парсеры и экпортеры данных. Встроенных средств php вполне достаточно. Кроме того PHP умеет кешировать opcache.enable=1 в php.ini и файл находится в памяти в откомпилированном виде. При сохранении его на диск вызывается функция opcache_invalidate() которая заставит PHP перечитать файл при следующем его включении в код командой include().

Структура папок

Все файлы CMS хранятся в папке .cms что позволяет в корне сайта размещать что угодно, в том числе и сгенерированные страницы. И последующее к ним обращение из браузера не запускает CMS. Файлы отдаются с диска веб-сервером.

Файлы и папки начинающиеся на точку считаются скрытыми и прямой доступ к ним запрещен. Но веб-сервер, через файл .htaccess, настраивается так, что всегда обращается к файлу .cms/index.php. Если приходит запрос /mytpl/css/style.css, то идет попытка найти файл .cms/mytpl/css/style.css, и если он есть то он копируется в корневую папку по пути указанному в запросе и отдается браузеру. Если на диске уже имеется такой файл, то он не перезаписывается. Единственная тут странность в том, что если файл был на диске, то такого запроса к CMS быть не может. Но на самом деле может, если два запроса поступили почти одновременно и файл еще не успел создаться. Но ничего страшного не произойдет, второй файл перезапишет первый. Создание файлов в корневой папке происходит атомарно и веб сервер не может отдать частично записанный файл.

Меню в шаблоне

В админке можно настроить каждое меню, в какую область его выводить. Список областей и переводы на разные языки задаются в файле template.settings.php лежащем в папке шаблона. Пример того как это делается можно подсмотреть в шаблоне mini в файле .cms/mini/template.settings.php.

Если вы хотите сделать сайт на разных языках, в шаблоне проверять условия и в зависимости от условий выводить меню на русском menu( "header_en" ); или меню на английском menu( "header_en" );, то недостаточно добавить эти строки. Нужно так же описать области в файле template.settings.php. Без этого вы не сможете в админке настроить какое меню куда выводится. Админка просто не будет знать об этих областях.

// Берем имя текущего шаблона
$tpl = $cms["config"]["template.mod.php"]["template"];
// Определяем переводы меню для админки
$cms["lang"][$tpl]["ru_RU.UTF-8"]["Header Ru"] = "Верхнее на русском";
$cms["lang"][$tpl]["ru_RU.UTF-8"]["Header En"] = "Верхнее на английском";
// Описываем области
$cms["menu_areas"]["header_ru"] = __( "Header Ru", $tpl );
$cms["menu_areas"]["header_en"] = __( "Header En", $tpl );

Как происходит процесс обновления

В модуле admin.mod.php есть функция cms_update_cms_update() и алгоритм ее работы такой:

Сначала она проверяет что есть информация о новых версиях, полученная при нажатии на кнопку "Проверить" в разделе "Модули". Что прошла хотя бы минута с последнего нажатия на кнопку обновления. Что присутствует файл .cms/filelist.php, в котором перечислены файлы, их размеры и контрольные суммы.

Затем идет еще две проверки что новая версия больше чем текущая, просто сравниваются две строки. Вторая проверка - совместимость новой и текущей версии. Изредка CMS будет терять обратную совместимость и в этом случае, чтобы не сломать сайт, обновление с помощью кнопок в админке будет отклонено.

Затем идет проверка текущих файлов на изменения. Если хотите обновить измененный файл, то достаточно в .cms/filelist.php поставить пустую sha1 или в 0 размер файла.

Следующий этап - проверка прав файлов, иначе могут быть ошибки при удалении старых файлов.

Затем скачивается новая версия, если существует папка .tmp она удаляется и пересоздается. Скачанный .zip файл записывается в эту папку. Распаковывается в эту же папку.

Затем загружается файл .tmp/.cms/filelist.php и проверяются контрольные суммы файлов.

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

Затем файлы копируются из папки .tmp в папку .cms, но при этом так же проверяется не существует ли файл в папке .cms и не изменена ли sha1 и нахождение его в списке разрешенных. Если это так, то копирование пропускается, иначе происходит копирование.

Если в процессе возникнут ошибки, то пользователю об этом будет уведомление. Затем папка .tmp удаляется.

Считывается файл .cms/update.sql и выполняются запросы к БД из него. Это позволяет изменить базу данных под новые возможности.

Иногда могут потребоваться более сложные действия чем закидывание новых файлов, для этого существует файл .cms/update.php. Если он существует, то загружается и соответственно исполняется.

Затем идет установка переменной $cms["config"]["admin.mod.php"]["clear_cache"] = true; Чтобы в процессе перезагрузки админки после обновления еще раз было произведено удаление статических файлов сайта с диска. Для какого случая это нужно - нужно еще вспомнить. И прямо сейчас тоже выполняется очистка от статических файлов.

Пользователю отправляется сообщение что обновление успешно произведено. Админка перезагружается спустя 5 секунд когда сообщение исчезнет.