Pull to refresh

Пишу CMS на PHP. Часть 2

Reading time4 min
Views9.9K
PHP

Несмотря на многочисленные попытки отговорить меня от данной затеи, я все же продолжу как и планировал. Каждый комментарий предыдущей части, я прочитал и учел. Встретил как собственные пожелания некоторых людей, так и настоятельные рекомендации не крутить собственный велосипед. Мне понравились комментарии ainu и Fesor, на мой взгляд — очень конструктивное мнение о том, чего не хватает в CMS & Framework на сегодняшний день. К примеру реализация задачи по быстрому и простому способу создания блога для человека, которому довольно сложно объяснить как им пользоваться — чрезвычайно сложна по своей природе. А поскольку подобные задачи появляются все чаще и чаще, я и решил заняться вплотную данной идеей.

Вы можете себе представить насколько удобно можно реализовать интеграцию социальных сетей, API Аналитики и прочих «сладостей» нынешних возможностей мира информационных технологий для конечного пользователя? Насколько простым и интуитивным можно сделать интерфейс информационных ресурсов? Я могу довольно долго продолжать описывать мои идеи и цели, но пока это происходит, прогресс не идет, а значит время тратится впустую. Ко всему этому мы дойдем в следующих частях моей серии статей, а пока — по делу.

Иерархия поддиректорий проекта


  • engine
    • Service
    • System

  • module
    • Module
    • ...

  • public
    • Downloads
    • ...

  • view
    • Theme
    • ...



Очень часто работая с крупными проектами встречал огромное количество папок содержащих тот, или иной «жизненно важный» компонент работающей системы. Чего нельзя сказать к примеру о Django / Symfony. Каждая их папка отвечает за собственный автономный в той или иной мере компонент, изначально подразумевающий выполнение определенных целей. То же самое можно сказать о многих других фреймворках, но сейчас не об этом.

Папка engine будет содержать системные классы, а также сервисы обеспечивающие выполнение той или иной задачи.

Папка module включает в себя контроллеры с описанием роутинга, конфигурационными файлами, файлами кеша, трейтами.

Папка public содержит файлы, к которым предполагается непосредственный доступ со стороны клиента посредством выдачи сервером напрямую. Иными словами — файлы для скачивания пользователями.

Папка view будет содержать в себе папки тем оформления со всеми необходимыми компонентами в виде каскадных стилей, скриптов, исходников sass, картинок и прочего видимого медиаконтента.

Архитектура


В прошлой статье, меня увлекли в незнании паттернов проектирования. В свое оправдание могу сказать что паттерны проектирования уместны не во всех ситуациях. К примеру используя MVC/HMVC, я бы с легкостью смог спроектировать WEB-Приложение на PHP. Но если взять тот же Pattern Facade или Observer, общая картина становится не такой уж очевидной, хотя и представить ее можно.

Для более наглядного объяснения чего я хочу добиться, приведу пример реализации авторизации пользователя на Django (Python):
def auth_controller(request):
    user = authenticate(username=request.POST['username'], password=request.POST['password'])
    if user.is_active:
        login(request, user)

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

Сам же модуль, будет реализован по похожему принципу но с некоторыми нюансами. Часто случается необходимость в реализации элементарного API, что с использованием CMS — довольно громоздкая и сложная задача, если это не предусмотрено самой системой. По-этому, точкой входа каждого модуля будет родительский метод базового модуля — "request", аргументом которого будет объект, который будет содержать средства изменений результирующего набора заголовков. Таким образом, мы добьемся максимально модифицируемый и удобный интерфейс модификации ответа сервера по тому или иному запросу, что и является главной задачей нашего контроллера.

Как наглядный пример — реализация RSS:

namespace Module/News;

class RSS {
    public function request($request) {
        $request->response->headers['Content-Type'] = 'application/xml';
    }

    public function route($router) {
        $router->map('^rss\.xml$', [$this, 'feed']);
    }

    public function feed($io) {
        return $this->service('Rss', $this->service('News')->getLatest(0, 50));
    }
}

Пример довольно грубый и не показывает всю идею того что я хотел показать, но как ранее я уже упомянул — модули могут содержать traits, в которых для наглядности мы можем хранить наши контроллеры. А уж если модуль слишком объемный, ничего не мешает в роутинг передать callback вида «Module/News/Feed::xml», с того же пространства имен.

В заключение


Как всегда, жду конструктивной критики с Вашей стороны. В следующей части, учитывая комментарии к этой статье, выложу все учтенные правки, благодарности, и репозиторий Github. Всего доброго!
Tags:
Hubs:
Total votes 42: ↑9 and ↓33-24
Comments69

Articles