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

    Имея более чем достаточно времени, увлекся я размышлениями о создании гибкой, многофункциональной, но относительно простой 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
    Продолжение: Модель данных
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 76

      +1
      Некоторые моменты напоминают мою cms, но все равно в целом архитектура несколько другая. Согласен с тем, что про генерацию страниц и поддержку модульности надо писать отдельно, это на мой взгляд одна из самых интересных частей в подобных системах.
        0
        Самое интересное, что Вовка действительно описывает свою CMS, которую делает от начала до конца сам.
        Концепция очень интересная, а то, что действующий (пусть ещё с очень большими недоработками) прототип системы уже существует, оставляет надежду на то, что проект будет будет доведён до стадии продукта.
          0
          Эх, многие из нас когда-то рисовали такие схемы и писали системы…
          Это классный опыт ;-) Искренне желаю удачи!
            0
            С интересом прочитал. Наверно, каждый второй программист пробует сделать свою cms или фреймворк. Я тоже отношусь к этим «кадым вторым».

            И по теме, а какой модуль у Вас определяет какой именно алгоритм(модуль) логики запускать? Request? Или модули отвечающие за логику вешаются на событие?
            И каким образом определяется порядок вызовов обработчиков событий (порою это может иметь критическую важность)?
              0
              Прочитал не отрываясь. Очень интересно. Огромное спасибо. А будет ли продолжение?
                0
                Продолжение будет и много))
                Логика определяется набором модулей. Да, модули вешаются на события, и есть нерешенный вопрос об определении порядка вызова обработчиков одного события, например модуль страниц должен работать после того как модуль данных сохранит входящие данные… Но лучше не мудрить с событиями и просто повесить модуль страниц не на модуль запросов, а на модуль данных… т.е. когда модуль данных обработает входящие данные.
                  0
                  Спасибо статьи про архитектуру всегда интересны! Вот только было бы здорово, если бы называли вещи по стандартной терминологии. Думаю, многим бы стало всё понятнее, если бы сказали, что запросы система обрабатывает по паттерну Front Controller, модули взаимодействуют по паттерну Observer, при доступе к базе данных используется Data Mapper в виде репозитария объектов. И несколько непонятно, как реализуется непосредственно логика работы приложения. Например, банальное добавление комментария. Хотелось бы простой пример именно на уровне кода или подробные диаграммы классов и последовательностей для типичной веб задачи. Больше картинок меньше слов :-)
                    +1
                    Кстати, да!
                    Диаграммы последовательностей для понимания как работаю внутренности архитектуры рулят!
                      +1
                      Не надо в паттерн-терминах, пусть язык описания останется проще.
                      0
                      Пишите дальше :)
                        0
                        Кстати, система с событиями называется Signal/Slots, в фреймворке ezComponets реализовано, не так давно писал про это как раз. очень мощная и гибкая штука
                          0
                          Вопрос, а как система узнает, какой нужно дать отклик (реакцию) на действие пользователя? Посредством урл? Если так, то хотелось бы увидеть, как выглядят эти урл (надеюсь они не тупо хранятся в БД)
                            0
                            Модуль, который формирует вывод, в частности модуль Page смотрит параметры юрла и генерерит страницу, ссылки создаются под его контролям (точнее он определяет параметры для ссылки), поэтому он знает как на них реагировать. Впрочем вопросов ещё дофига)
                              0
                              А можно примеры урлов? И где они хранятся?
                                +1
                                Говорить об юрлах подробно пока сложно — много спорных решений, поймите, что проектирование ещё продолжается. Сейчас тестируется такой вариант:

                                url = http://boolive.ru/news/sports&2
                                $params = array('news', 'sports'); // переменная - это так образно
                                $args = array(2);
                                 

                                Первый параметр приводит к выводу блока новости
                                Блок новости фильтрует содержимое по второму параметру
                                Для вывода данных по страницам использует специальный элемент-блок, для него аргумент — это номер страницы

                                Пока это странно и возможно плохо понятно и не обасновано…

                                Вот ещё:

                                http://boolive.ru/news/sports/15&edit


                                Здесь третий параметр — это идентификатор объекта данных, в частности новости, а аргумент определяет действие над новостью, в частности отобразить форму для редактирования.

                                Юрлы пока нигде не храняться. Вы затронули тему, которая ещё изучается) Я собственно статью и написал, чтоб колективно решать вопросы архитектуры cms.

                                чистые ссылки преобразуется как у друпала:
                                http://boolive.ru/news/sports/15&edit => http://boolive.ru/?q=news/sports/15&edit
                            0
                            Интересно, спасибо! Кстати, а ваш проект по этой схеме опенсорс? Если да, то выкладывать будете что-нибудь?
                              0
                              Будем, нада доделать некоторые базовые модули, чтоб архитектуру в действии показать. А так, если интерисующихся много окажется, то открою svn
                                0
                                Я и два не хабра-контакта, которым я отправил ссылку, заинтересовались. Так что уже как минимум 3 человека ;)
                                  0
                                  Даже это радует)
                                    0
                                    Я тоже хотел бы посмотреть на реализацию, интересный подход.
                                      0
                                      +1, так что нас уже минимум четверо
                                0
                                А можно узнать чем рисовались схемы?
                                  0
                                  Только не смейтесь) во флеше
                                    0
                                    Прикрутите иерархию ;)
                                    Тогда можно ограничится одним контроллером, который будет все модули «разгребать».
                                      0
                                      Вы имеете в виду модули выстроить в иерархическую зависимость-связь?
                                        0
                                        Начать надо с иерархии объектов.
                                        Потом, «научить» этому контроллер (от этого он станет более гибким и универсальным). Кстати в вашей архитектуре, я заметил, контроллер стоит как-то в «стороне».
                                        При таком раскладе, модули можно не выстраивать в иерархической зависимости. Они контроллером уже будут вызываться иерархически. И «таскать» данные по модулям. В конце иерархии, данные будут содержать все что вам нужно, останется только их вывести, посредством модуля view (шаблонизаторов и т.п.).
                                        Может я не совсем понял объяснение на пальцах, но на мой взгляд у вас есть проблемы с контроллером и иерархией вызовов
                                          0
                                          Если под объектами вы имеете в виду данные, которые я тоже называю объектами, дополняя их словом данные, то иерархия совсем не уместна, вы это поймете, когда я расскажу в новой статье про модуль данных. Модуль данный – это как банк данных, некоторые модули участвуют (контролируют) в манипулировании данными (создание/изменение/удаление/чтение), другие модули пользуются этими данными, например модуль страниц Page. Получается, что тоталитарного контролера нету, есть например контроллер-модуль страниц, который управляет отображением данных в html формате. Самое интересное, что есть данные так таковыми данными и являющиеся (статьи, фотки, категории…), а есть данные-представления – блоки, вьюшки… Чувствую без новой статьи сложно понять))

                                          Если речь об иерархии, как о последовательности работы модулей и применения паттерна «цепочка обязанности», то этот вариант ещё возможен. Но реально он ничего не меняет. Посмотрите на рисунок событий – вроде иерархия. Но если отобразить все события, то будет не иерархия, а сеть. Не получиться выстроить последовательность работы модулей в иерархию.

                                          Вот пример:

                                          Как по рисунку событий в статье, выполняются события… модуль Request вызвал событие AFTER, первым его обрабатывает модуль данных Data, модуль Page ожидает своей очереди (он тоже зарегистрирован на AFTER), но вдруг в модуле Data возникает сбой, допустим, не может подключиться к БД – ошибка! Ошибка перехватывается модулем Errors. и модуль ошибок генерирует свое событие. На рисунке это событие не связано с модулем Page, но на самом деле модуль Page обрабатывает это событие – ему незачем ждать, когда придет его очередь от модуля Request!!! Несмотря на ошибку, модуль страниц корректно срабатывает и выводит красивую информации об отсутствии доступа к сайту.
                                            0
                                            Контроллер должен разделять и властвовать ;)
                                            У вас модуль, может я на пальцах чего-то не понял?
                                            0
                                            Таскать данные по модулям? зачем? Зачем передавать модулю то, что ему, скорее всего, не надо? модуль сам берет только то, что ему надо. Передаётся только управление. И как уже показал, возникают исключения, которые нарушают строгую иерархию передачи управления – возникает что-то типа сети.
                                            Есть одна проблема, я её где-то озвучивал — если у события несколько обработчиков, то от последовательности вызова обработчиков будет зависеть правильность функционирования системы. Вот что нужно как-то решить. Есть вариант в таком случаи вешать на события того модуля, после которого нужно работать. Но и здесь но! А если такой зависимый модуль устанавливается в систему как дополнение??? О нем же никто не знает, не знают, что нужно только после него работать?… думать нужно)
                                              +1
                                              И еще, я не увидел в вашей архитектуре CMS модуля кеширования. На сегодня это самый главный модуль.
                                              Далее, вы продумали расширения БД? Сегментирование и т.п… Если нет, думайте пока не поздно. Потому, что если не подумали, то ваша система будет работать только на не нагруженных проектах, а для этого существуют joomla и drupal ;)

                                              > вызова обработчиков будет зависеть правильность функционирования системы

                                              Вот, вот вы и сами понимаете, что контроллер ваш не совершенен, т.е. где-то не продумана архитектура. Совет, делайте настраиваемый (обучаемый) единый универсальный контроллер, который и будет работать и обрабатывать данные которые «таскаются» по модулям. Конечно, есть небольшая избыточность данных, но тогда сокращается код и выплывает гибкость системы, а это важнее. (кстати я свою архитектуру делал 2 года, переделывал уймы раз, первый вариант архитектуры был как у вас ;), но для расширения, гибкости и нагруженности пришлось все пересматривать ;) )
                                                +1
                                                Но подобная проблема остается и с контроллером. Да контроллер будет определять, кому работать, но кто будет определять само условие выбора совершаемого контроллером? Если устанавливается новый модуль в систему, то контроллер должен учитывать этот появившийся модуль. А от куда контроллеру знать, когда этому модулю следует работать? Ручки администратора?? Но тогда администратор может редактировать и порядок вызова обработчиков событий. Наверно. Хочется, чтоб все-таки модули сами устанавливались, настраивались и работали как надо.

                                                Что-то мне видится необходимость верных действий именно от человека для конфигурирования устанавливаемых модулей. Это как присоединение дополнительного жесткого диска в ПК требует правильной установки перемычки (Master/slave…) в самом устройстве.
                                                  0
                                                  >но кто будет определять само условие выбора совершаемого контроллером
                                                  Вот, вот подошли к самому интересному. :)))
                                                  Сама иерархия объектов — вот кто! ;)

                                                  Как? Могу объяснить более подробно, но в личной части habra.
                                                  Я свой проект уже закончил (на 90%). Дописываю админ часть.
                                                  Вначале я тоже шел вашим путем. Но смысла нет. Повторяются ошибки архитектур прошлых поколений cms.
                                                    0
                                                    так, мне кажется говорим мы об одном, а думаем о разном)) У узла иерархии могут быть несколько «детей» и порядок передачи данных/контроллера «ребенку» тоже будет иметь определяющее значение.
                                                      0
                                                      Правила, шаблоны правил.
                                                      Могу с уверенностью сказать, что вы это видите каждые день ;)
                                                      Даже, когда читаете почту в «почтовике» :)
                                                      Посмотрите вокруг. Файловые системы, почтовые клиенты, браузеры — все вокруг работает по этому принципу :)
                                                        +1
                                                        Так вот эти правила не могут быть статичными — они зависят от назначения модуля — «ребенка» иерархии — это не иерархия из однотипных элементов как файловая система. Это скорее сложный механизм типа радиоузлов телевизора
                                                          0
                                                          Не запутывайте. Все гениальное — просто.
                                                          Упрощаем и получаем гибкость ;)
                                                          Вы немного все запутали.
                                                            0
                                                            Вы делатете ошибку старых cms. Вы делаете отдельные модули: images, files и т.п.
                                                            Это ошибка. Обьект должен иметь тип. Для примера файловая система.
                                                            Есть понятие, допустим file, который имеет тип (расширение), например jpg. Контроллер (система) сама определяет что с этим типом делать и какие модули (программы) вызывать :) Все очень легко.
                                                            Тоже и в web — есть одно понятие у обьекта- content, который имеет тип.
                                                            Так же можно ссылаться на один и тот же обьект разными ссылками на тип.
                                                            Т.е. обьект может быть как page так и иметь ссылку на тип menu_left например.
                                                            :)
                                                            Продолжать?
                                                              0
                                                              да
                                                                0
                                                                Тогда contents — это файловая система. Контроллер — ос.
                                                                Модули — программы. View — обмен данными с контроллером и программой.
                                                                В такой конфигурации — главный кто? Правильно контроллер.
                                                                Файловая система — иерархия обьектов.
                                                                Правила — это поиск и вывод нужного набора файлов в зависимости от маски запроса (*.jpg — выводит весь контент для модуля галереи)
                                                                Пока я буду показывать параллели на пальцах, точнее файловой системой.
                                                                  0
                                                                  далее, пример правила (на основе файловой системы)
                                                                  c:/blog/*.blog
                                                                  что выведет — правильно все файлы *.blog
                                                                  Контроллер, если есть правило для blog, вызовет программы обработки файлов, и выведет то что нам нужно.
                                                                  Точно так же можно сделать и для обьектов в web проекте.
                                                                0
                                                                Постойте, но у меня модули не управляют типами. Модули image, file — они только добавлют немного логики для модуля данных. а таких модулей как новости, категории и всякие прочие типы, так таковых не существуют.
                                                                  0
                                                                  Этот хорошо. Модули, должны быть модулями — добавлять логику и всё. :)
                                                                  Я и писал — как мне кажется проблема с контроллером и управлением, а так же можно пересмотреть (определить) типы и ссылки на типы (да, да ссылки известные нам еще с с++, только в другой ипостаси).
                                                                  Все же тяжелова-то на пальцах.
                                                                  0
                                                                  Вы предположили, что модули системы определяют типы данных, т.е. для вас кроме модуля фотографий и файлов, я так понял, существуют образно модули сообщений, статьей, комментариев, каталогов и т.д., т.е. модули которые бы определяли и позволяли бы работать с разными типами данных. В принципе то, что мы можем наблюдать в большинстве CMS. Тогда такие вот модули конечно целесообразно было бы выстраивать в иерархическую зависимость, как нечто подобное наследованию классов.

                                                                  Обращаю внимание, что предложенная здесь архитектура совершенно иная. Если не заметно – модуль данных на рисунке самый большой и находится в центре, демонстрируя свою значимость. Именно этим модулем управляются данные – это как объектно-ориентрованная база данных. Все зависимости и отношения между данными, а также типы данных контролируются этим модулем. Другие модули, как и сам пользователь, могут создавать свои типы данных, но для этого используется модуль данных, т.е. типы данных создаются в этой самой как бы объектно-ориентрованной базе данных (модулем Data). Работа с данными четко выстроена, что не имеет проблем из-за внешних факторов, от таких как последовательность обработки событий.

                                                                  Один универсальный настраиваемый контроллер в системе есть – это совокупность модулей! Настройка контроллера сводится к установке/удалению модулей и регистрацией моделей на события. Вот как раз этот настраиваемый контроллер можно сравнить с электронной начинкой телевизора, модуль – это плата, для неё вроде есть разъем, воткнуть (установить) её просто, но есть ещё пара проводочков (обработчики событий) которые нужно так подсоединить в существующие разъемы, чтобы не нарушить общую логику работы телевизора (cms).

                                                                  Вот и получается, что нужно либо сводить на нет зависимость от последовательности обработки событий, либо просто писать инструкции по установки модулей))) типа измените порядок обработки событий так чтобы…
                                                                    0
                                                                    >я так понял, существуют образно модули сообщений, статьей, комментариев, каталогов и т.д.

                                                                    Хм. Ну, как сказать. Да, такое деление обязательно, но оно вторично. Задаётся просто дизайном и бэкендом данных.

                                                                    Одни объекты получают данные с БД, другие с файловой системы и т.п.

                                                                    Класс объекта может быть вообще пустой (просто нужно уникальное имя для, например, организации связок с другими объектами), если это страница фиксированного формата, в которой вся логика — лишь логика вывода и размещается которая в шаблоне. Может быть указан только механизм источника данных и, опционально, расписана структура источника. Скажем, если этот объект отображение MySQL-записи, то нужно будет указать hash-массив соответствия полей объекта и полей mysql-записи. Может быть указан особый механизм рендеринга, если это не страница, а, скажем, XML/RSS или картинка.

                                                                    И т.д. по нарастающей.

                                                                    >Если не заметно – модуль данных на рисунке самый большой и находится в центре

                                                                    В моём случае модуль данных — это равноценный среди других модуль. Да, чисто формально, мой storage_engine_mysql_smart — один из самых толстых модулей в системе, т.к. содержит в себе гибкую ORM, которая не только скрыто от программиста загружает объекты, но также умеет возвращать массивы объектов по условию, счётчики и т.п. Но вместо него спокойно может использоваться любой другой модуль-источник данных. На практике это реализованные oci (сейчас только R/O, писать в Oracle надобности ещё не было, понадобится — это будет пара десятков строк), xml/fs, *.txt/fs и т.д.

                                                                    >Один универсальный настраиваемый контроллер в системе есть – это совокупность модулей!

                                                                    Я, к сожалению, не очень понимаю, что Вы тут имеете в виду под контроллером. Явно не «C» в «MVC» :) Потому что если Вы имеете его в MVC-шном смысле, то «контроллер — совокупность модулей», понятие характерно для любой модульной системы.

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

                                                                    В моём случае именно так. Каждый объект системы — связка объектов движков. Именно плат, воткнутых в сокеты. Только у меня нет проводочков-событий, всё прекрасно работает и без них :)

                                                                    Ну, очень грубо, схема такая.

                                                                    Механизм загрузки объекта по имени и идентификатору:

                                                                    — Если такого класса ещё нет в памяти, то по имени определяем файл с классом объекта (я ранее писал про разделение ядра и расширений его, как хостовых, так и сайтовых + система укорачивания имён классов)
                                                                    — Создаём объект класса
                                                                    — Инициализируем его, если надо, загружая данные из БД.
                                                                    — Если всё успешно — возвращаем объект. Иначе — NULL
                                                                    — Опционально — кешируем объект в memcached и при следующих запросах (в т.ч. в других потоках) грузим кешированный результат.

                                                                    Выглядит для программиста это так:
                                                                    $topic = object_load("forum_topic", $id);
                                                                    или
                                                                    $last_topics = objects_array("forum_topic", array("last_post_time>" => time()-86400));
                                                                    или даже так:
                                                                    $last_user_topic = objects_first("forum_topic", array('user_id' => $user_id, 'order' => '-create_time'));

                                                                    Механизм загрузки объекта по странице сайта:

                                                                    Есть (также, раскиданные по уровням ядра и расширений) файлы, со статической привязкой регекспов URL'ов к классам:

                                                                    /forum/viewtopic.bas?id=(\d+)&p=(\d+) => forum_topic(1,2)

                                                                    1 и 2 — это группы в регекспе, в данном случае указывают ID объекта и номер показываемой страницы в нём.

                                                                    При нахождении соответствия загружается объект и вызывается его метод content(). Который, если не переопределён, сделат всё, описанно мной в этой теме чуть ранее. Сгенерирует содержимое тела страницы с помощью указанных механизмов шаблонизации (а данные уже загружены при загрузке объекта), поместит это содержимое в общий шаблон страницы сайта, если надо, закеширует объект, если надо — привяжет его к группам кешей, чтобы изменение объектов, от которых он зависит потом приводили к сбросу статических кешей и т.п.

                                                                    В конце явных поисков есть несколько записей вида:
                                                                    .* => page_fs_xml,
                                                                    .* => page_fs_hts,

                                                                    и т.д.

                                                                    Это классы, которые грузят объекты, описанные в файловой системе, параллельной структуре сайта. Иногда удобно сайт править удалённо по FTP, тупо работая с *.txt :)



                                                                    Когда страница будет отдана браузеру унифицированный модуль выхода проверяет, не изменялся ли объект и, если нужно, сохраняет изменения в бэкенде данных, попутно очищая/обновляя все зависимые кеши.

                                                                    Т.е. в явном виде сохранять изменения не нужно.

                                                                    Ну и плюс к этому механизмы администрирования, генераторы форм, проверка доступа и даже конфигураторы. Например, если ряд объектов имеет схожие настройки, например, один шаблон, один набор двжков и т.п. можно указать только конфиг-класс этих классов. И т.д. Всё это тоже задаётся либо указанием соответствующих движков, либо параметрами класса.

                                                                    Сами по себе разнородные объекты системы друг от друга структурно ничем не отличаются. Наследование, например, как таковое не нужно, применяется очень редко, когда реально нужно иметь несколько разных объектов с рядом схожих механизмов, или требуется расширить имеющийся объект, не трогая его.
                                                                      0
                                                                      сорри, но вы прокомментировали меня, исказив смысл сказанного. Никто не понимал, что существуют модули сообщений, статьей, комментариев, каталогов и т.д. Я предположил, что maxic посчитал, что в предложенной мною архитектуре применен подобный принцип. Поэтому он аргументировал применять иерархию, зная о неизбежных и серьезных проблемах с гибкостью при расширении функций cms с такой архитектурой.

                                                                      Если все очень очень сильно упростить, то модуль у меня – эта банальная функция. И чтоб расширить действия, которая она совершает, используются события. Вот и все. Модули у меня не генерируют свой контент, не владеют своими ORM, вообще ничто не делаю кроме своего локального назначения. Модулю вообще по барабану на всех)) т.е. дали порабоать, поработает, сделает свое маленькое дело и про всех забудет.
                                                      0
                                                      И еще вопрос. У вас блочно-модульная система или только модульная?
                                                        0
                                                        Если только модульная, тогда вы делаете систему как программист. Подумайте о дизайнерах, верстальщиках, обычных юзерах ;) Подумайте о юзабилити системы ;)
                                                          0
                                                          Блочная для генерации страниц
                                                            0
                                                            Вызов модулей в блоке в зависимости от данных в контроллере?
                                                            «Включение» (switch) модулей для блока и правила в контроллере ;)?
                                                            Иерархия блоков? (блок в блоке)?
                                                            Тогда вся CMS может состоять из одного контроллера, остальное — модули :)
                                                              0
                                                              не, архитектура вывода совершенно иная, о ней расскажу после статьи про модуль данных
                                                                0
                                                                Все же я упор бы делал на контроллер. Он должен все разгребать и управлять.
                                                                Смотрите не наступите на одни и те же грабли ;)
                                                                0
                                                                вот только про иерархию блоков угадали
                                                                  0
                                                                  Если так, то ваша диаграмма будет выглядеть еще проще :)

                                                                    0
                                                                    Вот вот, такую же диаграммку я только что нарисовал тоже, но ответа на вопрос, как контроллер будет самонастраиваться не нашел.
                                                                      0
                                                                      Ответ один — иерархия. У каждого кончено своя архитектура, но ответ будет такой. Реализация — в зависимости от проекта. А так как потомков может быть много — применяем шаблон/маску (поверьте, в самом простейшем виде).
                                                                        +1
                                                                        Поправлю слово, читать «конечно» :)))
                                                      +1
                                                      Очень интересный вариант — впечатлила продуманность. Я бы поправил только один пункт — конфиг выбирал бы по имени домена — очень удобный вариант, в отличии от одного config.php.

                                                      Так сделано в CMS, которую сейчас разрабатываем мы. Я тоже постараюсь выложить здесь описание структуры — тогда можно будет детально обсудить плюсы/минусы. :)
                                                        0
                                                        Взаимный обмен опытом будет полезен, ждёмс)
                                                          0
                                                          >Я бы поправил только один пункт — конфиг выбирал бы по имени домена — очень удобный вариант, в отличии от одного config.php

                                                          У себя использую тройную иерархию каталогов.

                                                          — Есть ядро системы, общее для всех проектов.
                                                          — Есть расширения хостинга, характерные для всего конечного сервера.
                                                          — Есть расширения виртуального хоста.

                                                          Лежать они могут в любом месте системы.

                                                          Когда ищется какой-то класс, include, шаблон, файл мапинга URL на классы или конфиг, он ищется сперва в виртхостовой структуре каталогов, потом в хостовой и, наконец, в основном ядре.

                                                          Таким образом обеспечивается и гибкая конфигурация, и переопределение функционала ядра без влезания в его исходники и т.п.

                                                          (На самом деле система даже ещё немного сложнее — дополнительно просматривается подкаталог vhosts/<имя_хоста>/ в хостовой структуре, куда могут класться виртхостовые же структуры — бывает удобно или просто необходимо в некоторых сложных проектах)
                                                          +1
                                                          Про структуру — чуть позже, а сейчас — о самом актуальном. Здесь — пост о разделении прав доступа в CMS. По моему получилось хорошо. :)

                                                          deniso.habrahabr.ru/blog/51231/
                                                            0
                                                            спасибо, интересно
                                                              0
                                                              можно поинтересоваться, в какой программе рисовали схемы? симпатично и понятно смотрятся…
                                                                0
                                                                комменты выше ответят на вопрос
                                                                0
                                                                извиняюсь, пропустил…
                                                                  0
                                                                  Мой фреймворк построен по подобной идеологии. Только абстракция немного иного уровня — вся система построена на единой система объектов. Все модули — суть объекты. В моей терминологии это — engines, движки того или иного функционала (т.е. «модули» для меня — вставки в шаблона). Соответственно, у каждого объекта могут быть движок исходных данных (обычно ORM), движок рендеринга основного контента, движок привязывания контента страницы к общему дизайну. Движки разделения доступа, кеширования, модулей в шаблонах, формирования типов ссылок и т.д. и т.п.

                                                                  Если интересно, поковыряться можно на hg.balancer.ru (GPL).
                                                                    0
                                                                    Модуль в терминах создаваемой системы — это статический класс

                                                                    Эээ, а тестировать эти самые модули вы как собираетесь со статическими модулям? пахнет жуткостным извращением) поправьте если ошибаюсь
                                                                      0
                                                                      А что не так с тестированием должно быть из-за статичности класса?
                                                                        0
                                                                        ну здрасте приехали, там где статик там мока быть не может у вас же вся функциональность на статиках как я понял, когда вы используете статик вы жестко привязываетесь к имени класса вместо того чтоб использовать имя переменной за которой может быть любой класс с любой реализацией, полиморфизм там все дела)
                                                                          0
                                                                          В том и дело что с модулями так и надо — напрямую обращаться к ним (либо через события), незачем модули представлять как объекты и передавать их куда-то в качестве аргументов, хранить ссылки на них и другое. Там где нужны объекты, используются объекты — всё в меру, всё для достижения гибкости и простоты. Сейчас на движке поднимается серьезный проект и поверьте, от того что модули являются статическими классами не возникло не малейшей мысли об ущербности. Возможно просто у вас свое представление, что должен делать модуль и почему он должен быть объектом. :)
                                                                      0
                                                                      что значит напрямую?) что мешает вам инстанционировать объект и обращаться напрямую к объекту?) используя статическое обращение к классам вы делаете архитектуру вашего фреймворка слишком жесткой, это касается далеко не только тестирования, также делает весьма ограниченным применение многих паттернов, ну и фактически лишает вас возможности использовать полиморфизм там где используется статическая привязка классов. Есть такие паттерны — Service Locator и Registry они в полной мере решают ваши проблемы с «вызовом модулей напрямую», в этом случае не нужно ничего никуда передавать в качестве аргументов. Боюсь это у вас уж очень особенное представление о том что является модулем, мыслей об ущербности и не возникает пока не возникает необходимость переделать чтото в уже рабочем проекте так чтоб это не зацепило за собой каскада изменений по всему коду, это все давно придумано и не мной вот:

                                                                      5 самых известных книг по проектированию и программированию

                                                                      1. Design Patterns. Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph E. Johnson, and John Vlissides
                                                                      2. Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant, and William Opdyke
                                                                      3. Patterns of Enterprise Application Architecture by Martin Fowler
                                                                      4. Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric J. Evans
                                                                      5. Working Effectively with Legacy Code by Michael Feathers

                                                                      Конечно не вижу того как вы используете статические члены классов, но для обработки действий юзера я не использую статики, потому что это поведение возможно захочется когда то переопределить. Я тоже использую статики в своем проекте, но исключительно в случае с утилитами, там где статический класс играет роль неймспейса, для объединения отдельных функций, относящихся к одной области, но при этом используемые отдельно, ну то есть не в рамках объекта, также есть статически дергаемый класс под названием Glob, в котором есть переменная $app — приложение и переменная $env, то есть окружение этого самого приложения, для обработки действий пользователя запускается обработчик событий так называемый роутер, но это не тот роутер что в зенде, он используется не только для урлов а вообще для всех событий системы, отдельные модули системы считаю вообще не должны напрямую дергать друг друга а должны взаимодействовать только по средсвам событий и их обработки это развяжет руки команде разработчиков, каждый будет писать свой код в соответствии с протоколом событий и их обработки, а также сделает код менее сцепленным и более независимым.
                                                                        0
                                                                        Вы не первый, кто упрекает меня в использовании статичных классов для модулей движка. Да что там, я сам, когда только начинал делать двиг, пытался сделать красивую правильную объектную структуру кода, в частности для модулей использовался паттерн singliton. Но когда прорисовалась полностью архитектура движка, решено было отказаться от правильной объектности в коде не в ущерб его гибкости, применение статичных классов для модулей только упростило программный код.
                                                                        Архитектура движка такая, что желание в будущем добавлять новую логику решается через обработку событий, незачем что-то переопределять, когда не нужное можно просто отключить. С умными книжками по ооп я очень даже знаком, даже более. Только вот идеология движка не в применении объектно-ориентированного кода, не в привычной всем реализации MVC и других штучек из книжек, а в гибкости модели данных и эта гибкость не достигается правильной объектностью программного кода. Незачем судить об использовании статических классов, когда вами не видна архитектура движка комплексно. Это не в обиду вам, но если увидите изюминку в архитектуре движка, а это в основном касается модели данных и её использования, то вопросы о статичности классов модулей уже не будут вас волновать.
                                                                        :)
                                                                          0
                                                                          Напоследок, гибкость модели данных на мой взгляд в реляционной БД может быть только в том случае если вы используете связь сущностей по графу, когда у вас в явном виде есть типизация сущностей, их связей, отдаленно это реализовано в друпале там есть понятие НОД но нет понятия связей нод и типов связей.
                                                                            0
                                                                            А здесь я только соглашусь. Именно в модели данных важна объектность для наделения графа семантикой, что и сделано
                                                                          0
                                                                          > Боюсь это у вас уж очень особенное представление о том что является модулем.

                                                                          Тут боятся незачем, я только рад что у меня оно особенное :)
                                                                            0
                                                                            >Тут боятся незачем, я только рад что у меня оно особенное :)

                                                                            Контекст) упускаете), особенности нашего мышления часто объясняются просто недостатком информации, проще говоря незнанием, но конечно все точки зрения имеют право на существование.

                                                                            singleton то тут причем? этот паттерн, который многие часто используют неправильно, синглтон нужен только в том случае если вам действительно так уж критично чтобы экземпляр объекта был единственный, синглтон также осложняет модульное тестирование ну и вообще нужно крепко думать прежде чем его использовать. Для доступа к звездным объектам обычно используют Service Locator или Registry

                                                                            >применение статичных классов для модулей только упростило программный код.
                                                                            Далеко невсегда самый простой путь является «правильным», но каждый сам выбирает себе путь что правда то правда) и понятие правильный весьма относительно, вашего «двига» я не видел и не берусь что либо утверждать да и даже еслибы видел ваш код то так как он не имеет непосредственного отношения ко мне то и высказывать какой либо негатив нестал бы, по кармическим причинам) (не на хабре)

                                                                            Вобщем желаю вам удачи в разработке вашего двига, как вы выражаетесь просто заметил для себя, что мне такой подход стал чуждым некоторое время назад ну и имел желание поделится своими соображениями.
                                                                              0
                                                                              Загибулина в том, что первостепенна цель, а не инструмент, абсурдно судить какой молоток правильный не зная какой гвоздь забивать. В общем, сколько не говори, как хороши всякие методики, паттерны и прочее, о каждом я знаю, но выбираю или придумываю своё, именно то, что лучшим образом приблизит цель к осуществлению.

                                                                              Спасибо за пожелания, приятно что спустя более полугода появляются новые комменты :)

                                                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                        Самое читаемое