Статьи
Портфолио
Друзья
Контакты

Последние статьи

15.10.2011 Zend Framework Day 2011, 12 ноября, Киев (0)

27.09.2011 MSSQL, XML и PHP. Как заставить это работать из под *nix? (0)

22.06.2011 Zend Framework, MSSQL и UTF-8 - проблемы с кодировками (5)

Все

Категории

PHP (2)

Zend Framework (32)

Javascript (4)

Другое (13)

Книги (1)

Все

RSS

Статьи

Комментарии

Портфолио

Облако тегов

программирование  open search  портфолио  php  zend framework  Zend_Db  Smarty  Zend_Form  паттерны  javascript  niceforms  jQuery  Zend_Mail  веб  Google  Zend_Rest  Zend_View_Helper  zend casts  Zend_View  Zend_Layout  speedUp  интернет  Загрузчик фотографий  Flash  ВКонтакте  zend  localization  zend_translate  gettext  Я читаю  Книги  sphinx  софт  массовые рассылки  хранение данных 

Все

Статистика



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

Главная > Статьи > Zend Framework > Практика построения модульной CMS-системы
04.02.09 Практика построения модульной CMS-системы

Модульное программирование в Zend FrameworkПеред тем как начать, хотел бы предупредить, что довольно много теории я описал в своей статье «Модульное программирование в Zend Framework», поетому очень рекомендую сначала прочитать ту статью, а потом перейти к чтению этого материалла. В той статье просто выложено основные теоретические понятия о подобном программировании — это избавит Вас от лишних вопросов. Итак, причины, преимущества и недостатки модульного программирования можно считать выяснили. Переходим к практике.

 

 

Практическое решение


Модульную информационную систему можно показать в виде наглядной диаграммы взаимосвязей:

 

Структура модульной CMS-системы

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

 

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

 

Суть построения движка, заключается в создании ядра и строго стандартизированного модуля. Каждая из частей такой системы имеет свои наборы моделей, контроллеров, видов. При старте нашего приложения, все управление системой перенимает на себя бутстрап-файл, где происходит её конфигурация и подключение плагинов фронт-контроллера.

 

Дальше управление передается плагину фронт-контроллера, который осуществляет маршрутеризацию для модулей. Т.е. у меня вся структура сайта хранится в БД по алгоритму вложенных множеств и к каждой ветке сайта прикрепляется метка и модуль, который отвечает за содержимое в данной ветке. Таким образом не нарушается целостность системы и остается техника ЧПУ.

 

Допустим Вы прошли по адресу http://web-blog.org.ua/news. Плагин разбирает, что за ветка сайта запрошена по заданой метке (news) и передает управление модулю (articles), отвечающего за вывод содержимого, предварительно загрузив с модуля нужные роуты для корректной дальнейшей обработки запросов системой.

Приблизительно, это выглядит так:

Код хорошо документирован, поэтому я не буду больше объяснять.

 

При программировании модульной CMS-системы, нужно использовать Zend_Layout, для шаблонизации. Но объяснение этих нюансов выходит за рамки статьи…

 

Далее по ходу действий, управление передается модулю, который должен «знать» текущую ветку (через Zend_Registry) и выдать необходимое содержимое, привязанное к ветке. Т.е. таким нехитрым образом реализуется возможность использовать один модуль, допустим, для 5-ти разных веток сайта и у каждой своё содержимое (пример: на блоге - «Статьи» и «Новости» управляются одним модулем - articles и у каждой свое содержимое), при этом таблица в БД — одна для всех веток.

 

Далее все происходит стандартно:

  • Обрабатывается действие модуля
  • Генерируется ХТМЛ конкретного действия
  • Вставляется в Layout
  • И вуаля — контент на мониторе

При использовании своего CSS-фреймворка, хорошо стандартизированного, иногда смену дизайна можно свести к замене картинок и CSS-файлов.

 

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

 

У меня, по-умолчанию, ядро тоже является модулем и исполняет функции обычных текстовых страниц.

 

Вопрос о программировании сайдбаров очень тонкий, но если использовать дополнительный контроллер, который занимается только выводом сайдбаров, то это тоже тривиальные вещи. Вытягивать срендереный сайдбар можно поблочно с помощью helper'a вида — Action.

 

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

 

Все полностью повторяется и для реализации админ-части приложения.

 

Все! Осталось только вникнуть в выше сказанное и написать необходимые модули. Система готова!

 

 

 

Итог


Статья даёт Вам возможность представить лишь один из множества вариантов решения данного вопроса и не претендует на полность его расскрытия. Все, что я выложил в этой статье, как видите, отлично работает ввиде этого блога…

 

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

Теги:  zend framework, программирование

Другие категории:

■ PHP ■ Zend Framework ■ Javascript ■ Другое ■ Книги
Комментарии к статье
  lcf

25.02.09 19:50:07

Классно блог обновился.

По поводу статьи - получается так, что модуль выходит жестко завязан на УРЛ? Мне кажется это не очень хорошей идеей, хотя для некоторых простых сайтов сгодится. Или я прочитал невнимательно? если так - то буду рад услышать разъяснения по поводу что такое label.

Вообще система выбора того какой модуль "играет" уже ведь есть в зф - маршрут и так определяет какой модуль будет выполнен. А в модуле уже можно реализовать наследование, какую-то свою любую логику и ответ тоже будет вставлен в лэйаут (или его можно в этом модуле сменить).

 

Однако есть проблема с маршрутами - да. С теми какие должны срабатывать заранее и как их грамотно определять для модулей. Я решил это (думаю что временно, но решение, как мне кажется более подразумевающее свободу действий чем предложенное в статье) с помощью расширения логики маршрутов. Не с помощью наследования, там это не получится, а с помощью добавления дополнительного параметра - приоритет маршрута. У меня в классе отвечающем за инициализацию приложения подключаются конфигурационные файлы содержащие маршруты (из всех модулей сразу), далее маршруты сортируются по приоритету (приоритеты заданы в виде констант специального системного класса и имеют вид типа System_Route::SYSTEM_PRIORITY, System_Route::STANDART_PRIORITY и так далее) и потом уже добавляются во фронт контроллер. Таким образом на момент $front->dispatch мы имеем полностью сконфигурированный фронт контроллер и логика поведения на основе строки запроса (урла) - прозрачна. Как мне кажется, ваш подход (Если я понял его правильно) конкретно вредит прозрачности и ограничивает программиста. Не сочтите за критику, просто мысли вслух.

 

PS: при попытке добавить комментарий:

"http://lcf.name" - это DNS имя хоста, но оно не соответствует TLD для TLD "name"
"http://lcf.name" - адрес является недопустимым сетевым названием местности

  illusive

26.02.09 13:13:47

Классно блог обновился

Спасибо.

PS: при попытке добавить комментарий:

"http://lcf.name" - это DNS имя хоста, но оно не соответствует TLD для TLD "name"
"http://lcf.name" - адрес является недопустимым сетевым названием местности

Адрес нужно вводить без "http://". Сделаю сообщения об ошибках более понятными. Спасибо.

По сабжу:

Вероятно Вы не до конца поняли суть работы такой модульной системы.

label - играет роль указателя на экземпляр модуля. Т.е. на блоге, модуль articles работает для 2-х веток сайта: статьи и новости. Если модуль называется articles - это не значит, что он будет работать обязательно по адресу http://web-blog.org.ua/articles/. Адрес я выбираю сам: я могу за 0.5 мин. сменить из админ-панели адрес "статей" блога на любое, напр., на "posts" или "topics" не потеряв содержимого.

Т.е. название модуля и метка - разные вещи. С помощью меток я делаю запись, по сути: адрес - модуль - содержимое.

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

 

Проходя по адресу /articles/ - модуль articles.

Проходя по адресу /news/ - тот же модуль articles.

Как модуль понимает какое содержимое выдать?

Очень просто:

Сравнивает id ветки на которую в БД записана запрошенная метка и выдает соответствующий материал. Т.е. если заведу адрес /test/ (создам новую ветку сайта с меткой test) и выберу из списка доступных модулей модуль articles, то модуль заведет отдельный, так сказать, namespace в своих таблицах, который равен id созданной ветки.

При удалении созданной ветки, модуль оповещается об этом и удаляет этот namespace из таблиц.

Как видите система совсем не привязана к URL и дает гибкие возможности как для программиста, так и для пользователя.

Благодаря такой организации, я могу к системе дописывать разнообразные модули, напр., модуль интернет-магазина или модуль гостевой книги - ограничений никах нет.

Вот еще бы систему оповещений грамотно написать, на основе паттерна Observer - это было бы, ИМХО, вообще супер.

  lcf

28.02.09 14:58:46

Ага, кажется... в общих чертах понятно.
 
>> Адрес нужно вводить без "http://". Сделаю сообщения об ошибках более понятными. Спасибо.

ну я понял конечно что надо с хттп вводить, я просто к тому что это не так очевидно и обычно его вводить не надо, поэтому момент не интуитивен, но дело ваше конечно что делать с моим фидбеком)

Еще вот что- специально поставил галочку что мол присылайте мне комментарии в ящик, на случай если вы чего нить ответите - но ничего не пришло. Ящик вы мой, по идее, должны видеть - гмайл, так что скорее всего у вас что-то не сработало. 

о. И ещё один "ps" - второй раз пишу комментарий и второй раз столкнулся, капча для размещения комментария очень хорошо читается, но время жизни очень малое, других причин почему ему мой код не понравился я не вижу. Щас еще раз протестирую ^_^ 

  lcf

28.02.09 15:07:33

7 минут и все код уже не правильный. 7 минут это достаточно мало, учитывая тематику ресурса, ИМХО. Ладно бы если б тут писали только "жжошь чувак, писши исчо")))

  illusive

02.03.09 09:58:06

Не знаю в чем проблема с письмами, но мне пришло 2 письма на meta.ua о Ваших комментариях.

 

Переввести капчу с 4-х символов нетрудно, поетому время жизни не буду увиличивать в целях безопасности.

ну я понял конечно что надо с хттп вводить, я просто к тому что это не так очевидно и обычно его вводить не надо, поэтому момент не интуитивен, но дело ваше конечно что делать с моим фидбеком)

Не совсем Вас понял, адрес сайта вводить надо без http://

  Диана

15.03.09 17:01:09

Спасибо большое, интересная статья, да и блог заметно улучшился, давно у Вас не была...

  illusive

16.03.09 12:21:19

Спасибо большое, интересная статья, да и блог заметно улучшился, давно у Вас не была...

Спасибо за поддержку Улыбается

  Мой профиль

25.05.09 11:06:31

откуда берется $request?

  illusive

25.05.09 12:03:34

$request - передается фронт-контроллером в функцию плагина как параметр

  Мой профиль

25.05.09 14:03:38

как ->url() в скриптах вида будет рендерится для не текущего модуля, если addroute произведен только для текущего?

  illusive

31.05.09 12:44:06

А зачем Вам ссылаться на другой модуль, если Вы не можете быть уверенным есть ли он вообще в системе?

Ваш модуль ничего не должен знать о других модулях...

  Serhio

05.07.09 12:25:43

Кому интересно - вот мой вариант установки ЧПУ. 404-е отстреливаются в errorAction. В категориях предусмотрен пейджинг

  illusive

06.07.09 18:09:01

@Serhio

На сколько я понял(быстренько просмотрел) Ваше решение не настолько гибкое (или вообще без модульности), как предложенное мной, ведь оно связывает модули конкретными роутами. А как же гибкость в наборах роутов для модулей и свобода в их программировании?

 

Например, в модуле "Контакты" два роута, а в "Статьях" шесть, и это действительно необходимо - мы же заботимся о ЧПУ. Как быть в этой ситуации с Вашим решением?

 

Ничего личного, только программинг Подмигивает

  Serhio

07.07.09 07:40:07

Именна та модульность, которую предусматривает фв зенд сама по себе не обладает достаточной гибкостью.

 

За 2 года коммерческого программирования, используя zend у меня небыло таких случаев когда я использовал более 2х модулей. default - фронт. admin - админка

 

Используя мой метод добавления роутов нада заботиться о том чтоб небыло:

 

http://site/about - раздел статей

http://site/about - о сайте

 

но это уже задача контент менеджера.

 

В более сложных системах сайтах использую

  illusive

07.07.09 15:54:34

Разделяя систему только на две части Вы не добиваетесь никакой модульности, а только нарушаете парадигмы модульного программирования. Прелесть модульности в том, что например, я положил модуль "Статьи" в папку "Модули" - в админке сразу же появился новый тип страници и я могу сколько угодно понасоздавать разделов, которые работают на модуле "Статьи" не дублируя программный код, ведь все красиво завернуто в БД.

 

Таким образом на сервере лежит только один экземпляр модуля, но он работает с разными данными (пример, на блоге раздел "Статьи" и "Новости" работают на основе одного и того же модуля в едином экземпляре, только с разными данными, которые никак между собой не пересекаются). Если вдруг я удалю папку "articles" из папки "modules" - то нерабочими станут сразу два раздела сайта.

 

Аналогично, в новой версии своей системы (блог работает на старой) есть еще и плагины, которые предназначены для работы с обобщенными данными (например, поиск по сайту).

 

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

 

Модульность от Zend Framework - лишь каркас для построения собственной архитектуры модульного приложения и не стоит боятся расширять его для собственных нужд.

  Smirna

22.07.10 09:02:01

Андрей, вопрос по лайоутам был упомянут, что это отдельная тема.
А данная тема появиться или как?
Я пока только начинаю присматриваться к ЗФ, но хотелось бы именно той модульности, что вы и описали тут - закинул модуль в папку модуьлей и ядро само определяет, что появился новый модуль - значит его можно использовать.
Идея очень хороша, пока не совсем понимаю всего что указано, так как с ЗФ знакомлюсь только, но блог отлично в этом помогает (уже в закладках через неделю как начал поиск инфы по ЗЫФ).

  illusive

24.07.10 17:31:56

Спасибо) Да, данная тема уже давно описана мной Zend_Layout - это просто! Шаблонизация проектов

  Smirna

26.07.10 08:19:48

Андрей, да, я читал эту статью, но не смог тогда понять, как там менять шаблоны, но это описано в документации, что не было освещено тобой.

Но я помню, что у тебя принцип: "Зачем описывать то, что уже есть в стандартной документации?!?" Да и самому было интересно и тогда перешел по последней ссылке в коментах и нашел достаточно удобный мануал по ЗФ (с учетом того, что я с аглицким не дружу почти, то для меня самое то).

Ну и ради любопытства перешел в раздел лайоутов и там в быстром старте описан как раз пример использования в определенном моуле своего шаблона, что меня очень порадовало - http://manual.zfdes.com/ru/zend.layout.quickstart.html

ЗЫ-1. Последний коммент какой-то в лайоутах не корректный, так что он закрывает возможность писать комменты.

ЗЫ-2. в этом визуальном редакторе комментов не работает кнопка "Del", что не очень удобно :)

  illusive

28.07.10 14:48:15

У меня все впорядке с редактором. Каким браузером Вы пользовались? Аналогично и со статьей про layout'ы все нормально..

  Smirna

28.07.10 16:02:08

с работы пользоваться могу только ИЕ8.

  illusive

29.07.10 11:37:15

Да, действительно в той статье ИЕ некоректно отображает содержимое. Попытаюсь разобраться, но моя аудитория с ИЕ это очень малый процент

  FRM

30.03.11 19:48:56

  1. $frontController = Zend_Controller_Front::getInstance();  
  2.         /** 
  3.          * Роутер 
  4.          */  
  5.         $router = $frontController->getRouter();  
  6.         /** 
  7.          * Парсим запрос, чтобы выделить метку с адреса 
  8.          */  
  9.         $newRequest = $router->route($request);  
  10.         $label = $newRequest->getParam('label','');
  11. Если я правильно понял вы таким образом хотите получить label, т.е. если взять ваш пример с http://web-blog.org.ua/news, то в label должно быть news. Мне не понятно каким образом у вас появлся параметр label до маршрутизации? Вы пробовали получить label таким образом? Если да то буду признателен если поясните этот момент подробнее. 
  illusive

07.04.11 11:01:49

Я программно "заставил" роутер провести маршрутизацию, получив label оттуда.




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

  Suhoij

08.11.11 16:04:49

Чтобы сделать систему гибче и убрать связанность модулей - желательно ввести в ядро больше событий(Например block_render_begin, block_render_end). Можно воспользоваться например http://components.symfony-project.org/event-dispatcher/.

Оставить свой комментарий

 
Статьи | Портфолио | Друзья | Контакты
Идея и мозги: Васильев Андрей © 2008-2011 Web-Blog Кисточка и фантазия: Зелинский Богдан