Как стать автором
Обновить

Архитектура CMS

CMS *PHP *
Имея более чем достаточно времени, увлекся я размышлениями о создании гибкой, многофункциональной, но относительно простой CMS для программистов и её конфигураторов-пользователей. Некоторые идеи были навеяны потенциальными возможностями CMS Drupal. И вот теперь, увлеченный уже реализацией идей и имея успешные промежуточные результаты, я решил рассказать об архитектуре создаваемой CMS. По ходу прочтения общая картина возможностей CMS должна прорисовываться сама, во всяком случае, для программистов:)

Архитектура CMS


Архитектура создаваемой системы основана на модульном принципе. CMS полностью строится из модулей, как детский домик из кубиков. С целью достижения гибкости и простоты взаимодействия модулей, необходимо было достичь минимальных действий для использования модулей любым компонентом системы без необходимости создания жестких связей, а также сделать возможность легкого расширения действий модулей с помощью других модулей.
CMS — совокупность модулей
Рис 1. CMS — совокупность модулей

Модуль


Модуль в терминах создаваемой системы — это статический класс, имя которого определяется именем модуля. Для функционирования многих модулей недостаточно одного статического класса — могут применяться дополнительные программные структуры, реализуемые в отдельных файлах. Все файлы модуля размещаются в одной директории (папке), а директории модулей в modules.

Структура файлов CMS
В корне web-директории существует файл index.php и файл базовых настроек config.php. При любом запросе к сайту, сервером исполняется файл index.php, именно с него начинается функционирование системы.

Системный модуль System


В index.php подключается системный модуль System и файл конфигурации config.php. После загрузки конфигурационного файла, управление передается системному модулю.
Запуск системного модуля – ядра cms
Рис 2. Запуск системного модуля – ядра cms

/** 
 * index.php 
 * Главный исполняемый файл. 
 */  
// Подключение системного модуля для обеспечения автозагрузки и работы других   
// модулей  
require('modules/system/System.php');  
// Файл конфигурации  
require('config.php');  
// Запуск системного модуля  
System::Process(); 

Системный модуль обеспечивает автоматическое подключение всех остальных модулей и является ядром системы, приводя её в исполнение. Автоматическое подключение модулей обеспечивается php-функцией __autoload($class_name). Данная функция определяется в файле системного модуля, но вне его класса. При обращении к незагруженному классу, PHP интерпретатор обращается к этой функции, функция, в свою очередь, обращается к системному модулю. Системный модуль определяет наличие запрашиваемого класса (модуля), местонахождение его php-файлов и подключает их.

/** 
 * Функция автозагрузки классов (модулей). 
 * Эта функция используется только интерпретатором PHP 
 * @param string $class_name Имя класса (модуля). 
 */  
function __autoload($class_name){  
    System::IncludeClass($class_name);  
}


После подключения файлов класса системным модулем автоматически вызывается статический метод Activate() подключенного класса (если этот метод есть), что позволяет статическим классам инициализироваться. Модули, как помните, являются статическими классами и многим необходима инициализация перед работой.

Таким образом, для использования модулей не надо ничего предварительно объявлять или подключать, достаточно просто обратиться к методам или свойствам класса модуля, и не нужно создавать ссылок (указателей) на модули. В этом заключается принцип простого использования модулей любым компонентом системы.

Модуль событий Events


Модуль событий Events предоставляет возможность модулям генерировать события. События генерируются вызовом метода Events::Send($module_name, $event_name). Обрабатываются события статическими методами классов других модулей, хотя ничто не мешает модулю обрабатывать и свои события.

Системный модуль System не определяет дальнейшее функционирование системы, он просто генерирует поочередно три события: «инициализация» (INIT), «выполнение» (START) и «завершение» (STOP).

static function Process(){  
    // Генерация основных событий:   
    // Инициализация  
    Events::Send('System', 'INIT');  
    // Выполннеие  
    Events::Send('System', 'START');  
    // Завершение выполнения  
    Events::Send('System', 'STOP');  
}  

Любой модуль может обрабатывать эти события и тем самым участвовать в функционировании системы. Но не только системный модуль генерирует события. На рисунке показаны основные события системы (кружочки) и их связи (линиями в полоску) с модулями, обрабатывающие события.

Основные события
Рис. 3 Основные события

Модули, генерирующие события, не знают кто их события обрабатывает. Любой модуль может зарегистрироваться на обработку любого события. Регистрацию на событие достаточно сделать один раз при установке (инсталляции) модуля. Сохранность информации о том, какой модуль на какое событие зарегистрировался, обеспечивается модулем событий Event. Ниже приведён пример регистрации и удаления её на событие «инициализации» (INIT) системного модуля System модулем ошибок Errors.

/** 
 * Установка модуля ошибок 
 */  
static function Install(){    
    // Регистрация на события инициализации системы  
    // Аргументы:   
    // Модуль-источник, Имя события, Модуль-приемник, Имя метода-обработчика      
    Events::AddHandler('System', 'INIT', 'Errors', 'Process');  
}  
/** 
 * Удаление модуля из системы 
 */  
static function UnInstall(){  
    // Удаление регистрации на событие инициализации системы      
    Events::RemoveHandler('System', 'INIT', 'Errors', 'Process');  
}

Применение событий позволяет расширять действия модулей, генерирующих события, либо просто реагировать на действия этих модулей.

Кстати, вспомните, как загружаются модули — только при первом обращении к ним. Это значит, что перед генерацией события START системным модулем, загруженными будут только сам системный модуль System и модули событий Events, ошибок Errors и сессий Session. Модули Errors и Session загружены, так как обрабатывали событие INIT, а модуль Events загружен, так как его использовал системный модуль.

Модуль ошибок Errors


Событие «инициализация» (INIT) системного модуля первым делом обработает модуль ошибок Errors, при этом он ещё и автоматически загрузиться. Модуль ошибок переопределяет стандартные обработчики ошибок и исключений PHP. Детально о нем пока говорить незачем. Можно упомянуть только то, что модуль ошибок в свою очередь генерирует события после обработки ошибок, что позволяет независимо от причины возникновения ошибки сформировать понятный ответ пользователю модулями, формирующими вывод, например, модулем Page.

Модуль сессий Session


В работе модуля сессий Session нет ничего особого, модуль запускается при событии инициализации системного модуля, определяет идентификатор сессии пользователя и после предоставляет доступ к данным сессии как модуль запросов Request.

Модуль запросов Request


Событие «выполнение» (START) системного модуля обрабатывает модуль запросов Request. Модуль запросов собирает все поступившие данные от пользователя в «контейнер», из которого они будут доступны любому модулю системы. Чтоб получить данные из «контейнера», нужно указать формат — тип и ограничения размера ожидаемого значения. Таким образом, в какой-то степени предотвращается проникновение данных, не соответствующих требованиям модулей. После завершения процесса помещения входящих данных в «контейнер», модуль запросов генерирует событие AFTER о завершении своей основной работы.

На поступивший запрос пользователя, как правило, необходимо сформировать вывод — ответ, и отправить его клиенту. Ответом обычно является html страница, но им может быть документ в ином формате, например XML, или файл, или что-то другое. В зависимости от параметров запроса пользователя (url’a), определяется один модуль для формирования вывода, точнее каждый модуль вывода сам определяет, работать ему или нет таким образом, что в итоге только один модуль отвечает за формирование вывода. Модули вывода начинают свою работу, обрабатывая событие AFTER модуля Request, что позволяет легко добавлять новые модули для формирования вывода в иных форматах. В принципе, любой модуль может быть модулем вывода, если будет хоть что-то передавать пользователю.

Перед формированием вывода, необходимо обработать входящие данные. Ими могут быть данные форм, которые следует сохранить в системе. Этим занимается модуль данных Data, обрабатывая событие AFTER модуля Request.

На рисунке стрелками отображен поток данных: пользователь выполняет запрос к серверу (передаёт данные), полученные данные обрабатываются модулями системы, каждый модуль выполняет свои действия с данными, в итоге формируется результат, который передаётся пользователю. Данные передаются прямым обращением к методам или свойствам модуля. Модуль, принимающий данные, сначала их запрашивает. Например, модуль данных Data, обрабатывая событие модуля Request, начинает свою работу и первым делом обращается к нему же (к модулю Request) за данными.

Поток данных

Рис. 4 Поток данных

Модуль данных Data


Модуль данных Data — самый важный модуль системы, именно от его возможностей зависит гибкость и функциональная мощь системы. Модуль данных предоставляет общий доступ к данным. Позволяет их создавать, изменять, удалять, а также осуществлять поиск с мощными возможностями. Только модуль данных обращается к базе данных через модуль базы данных Database. Для работы с данными другие модули не используют SQL запросы, ими применяется простой, но гибкий способ описания условия запроса, а также методы для манипулирования данными. Модуль данных на основе условий создает SQL запрос к базе данных и возвращает объекты данных. Получив объект «Новость», можно без явного обращения к модулю данных узнать всё, что связано с новостью — хоть автора раздела, к которому принадлежит новость. Благодаря модулю данных, пользователь-конфигуратор (да и сама система) может создавать свои классы данных — свои структуры данных. Об этом и многом другом будет рассказано в следующей статье. Для ясности только добавлю, что класс данных не имеет прямой связи с классом структуры языка программирования.

Модуль данных тоже генерирует события, обрабатывая которые можно осуществлять дополнительные действия с объектами данных при их сохранении, чтении и удалении.

Модуль страниц Page


Модуль страниц Page, используя шаблоны оформления, формирует html страницу, которую потом отправляет пользователю. Страница формируется из блоков в соответствии с входящими данными — параметрами запроса (url’a). Модуль страниц интенсивно использует модуль данных, так как страница — это представление данных, да и многие фрагменты — блоки страниц — тоже являются данными. Принцип генерации страниц и все тонкости функционирования модуля — тема одной из следующих статей.

Модуль файлов Files и фотографий Image


Модули файлов и фотографий — это одни из тех модулей, которые дополняют действия модуля данных. Кроме того, модули файлов и фотографий, при установке в систему, создают соответственно классы данных «Файл» и «Фотография». После, при работе модуля данных Data с объектами этих классов, модули файлов или фотографий выполняют дополнительные действия. В частности, при создании объекта данных «Файл», происходит загрузка файла на сервер и сохранение его в файловой системе сервера. Модуль файлов также является модулем, формирующим вывод. При соответствующих запросах, модуль передаёт файлы пользователю для скачивания, при этом ведется контроль доступа, статистика и все что может делать система в целом.

Основная функция модуля фотографий — масштабирование фотографии. Так как фотография является файлом, то её тоже нужно уметь загружать на сервер, для этого используется модуль файлов.

Модуль действий Actions


Модуль действий Actions позволяет классифицировать и контролировать действия, совершаемые модулем данных Data над объектами. Условием совершения действия может быть теоретически любое логическое выражение: в нем может быть и проверка текущего пользователя (его свойств), и проверка объекта, над которым совершается действие, и другое.

Пример: модуль данных Data загружает данные из БД и генерирует событие чтения, которое обрабатывается модулем действий Actions. Модуль действий Actions проверяет условия данного действия и вычисляет возможность его совершения, логический результат вычислений принимается модулем данных Data, который просто подчиняется результату, то есть продолжает или завершает чтение объекта данных. Условие и действие тоже являются объектами данных. Разобраться в тонкостях функционирования модуля действий Actions и гибких возможностях контроля действий можно будет после изучения модуля данных Data.

Модуль форматов Formats


Задача модуля форматов Formats — предоставлять разнообразные форматы для значений. Например для строк форматами будут представления e-mail адресов, телефонов, форматы оформления (разметка). Формат — это объект данных, который связывается с объектом значения, что и определяет формат для значения. Модуль форматов не просто предоставляет объекты-форматы, он ещё и обеспечивает проверку значений на соответствие формату. Сама проверка происходит, когда модуль данных Data сохраняет объект данных. Также некоторые преобразования значения (форматирования текста, например) в соответствии с форматом происходят при чтении данных. С функционированием данного модуля есть ещё множество нерешенных вопросов. Работа продолжается.

Заключение


Я рассказал о двух способах взаимодействия модулей — при помощи прямого обращения к методам и через обработку событий. Другие затронутые темы касательно функций и назначения основных модулей рассмотрены поверхностно, только чтобы показать в целом картину функционирования системы.

Сайт проекта http://boolive.ru
Продолжение: Модель данных
Теги:
Хабы:
Всего голосов 43: ↑33 и ↓10 +23
Просмотры 15K
Комментарии Комментарии 76