суббота, 19 декабря 2009 г.

Структура папок CMS. [Внеплановая заметка]

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



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

  1. Ядро системы вместе с файлами фреймверка храниться отдельно от сайта. То что это может быть специальное место на сервере и все сайты могут иметь у себя лишь символическую ссылку (с случае *nix систем) — это дело Ваше, тут решать Вам, но для строгой структурности системы, ядро лучше располагать отдельно от остальной части системы. Права на запись в эту папку могут быть только у владельца всего этого добра. Сюда сайт писать ничего не должен, а значит лучше запретить.
  2. Модули лежат в одном каталоге (каждый модуль может быть так же символической ссылкой). Права на запись такие же как и для ядра. Шаблоны админки каждого модуля хранятся здесь же.
  3. Хранение переменных окружения системы в целом. Т.е. здесь будут основные файлы конфигурации ядра — например, доступ к БД, тема оформления всего сайта. Здесь же должны располагаться плагины и помощники расширяющие систему конкретно для этого сайта. Сюда сайт должен логировать ошибки своей работы. Права доступа более сложные — как минимум — возможность записи логов, на этапе разработки сайта — запись конфигурации, редактирование темы оформления.
  4. Хранение переменных окружения модулей. В этой папке должен быть набор папок повторяющих набор модулей доступных для сайта. Здесь будут храниться настройки каждого конкретного модуля, его шаблоны, собственные плагины и помощники переопределяющие стандартные для модуля (если требуется специфический функционал модуля для конкретного сайта).
  5. Папка для хранения кеша.
  6. И, наконец, папка смотрящая «в мир». Т.е. папка доступная извне.
Такая структура позволяет иметь несколько сайтов (при использовании символических ссылок) на одной копии кода. Раздельное хранение параметров ядра и всех модулей дает возможность избежать путаницы при росте системы, а так же, дает возможность с минимальными последствиями переносить уже настроенные модуля на другие сайты.

Да, это накладывает некоторые строгие требования на стиль программирования, но программирование штука, сама по себе, строгая и требует ответственности.

Итак вот что у меня получилось в результате:

|-- CORE                    -- главный каталог системы, на него даются символическая ссылки в каждом сайте
|   |-- engine              -- папка приложения ядра
|   |   |-- config          -- конфиги системы (почти не используются, т.к. все важно вынесено в конфиги конкретного сайта)
|   |   |-- controllers     -- контроллеры ядра, все вызовы проходят через них.
|   |   |-- helpers         -- файлы с функциями-помощниками
|   |   |-- language        -- языковые пакеты системы -- только базовые объявления характерные для фреймверка или ядра
|   |   |   |-- english
|   |   |   |-- russian
|   |   |   `-- ukrainian
|   |   |-- libraries       -- фактическое ядро. Набор библиотек реализующих API ядра для работы всей системы.
|   |   |-- models          -- модель данных ядра.
|   |   `-- plugins         -- плагины системы. Фактически то же что и helpers, но несут другую смысловую нагрузку
`   `-- system              -- Фреймверк CodeIgniter

|-- modules             -- модули системы. Здесь лежат ВСЕ доступные модули. Фактически отдельные приложения. Каждый модуль -- симлинк на основной репозитарий.
|   |-- admin           -- -- модуль админ-панели
|   |-- categorys       -- -- категории 
|   |......
|   `-- user            -- -- пользовательская авторизация
|       |-- config      ----- Далее представлена структура папок модуля, повторяющая стандартное приложение на базе CI
|       |-- controllers
|       |-- libraries
|       |-- models
|       `-- views
`           `-- adm     -- ВАЖНО! Шаблоны Админ части модулей находятся именно среди общего репозитария. Т.е. едины для всех сайтов

Далее, набор папок относящихся к конкретному сайту

|-- cache                   -- 755 (www-data) Кеш системы. Кеш для данных
|   `-- full_pages          -- 755 (www-data) Постраничный кеш.
|-- main_vars               -- Переменные окружения ядра
|   |-- config              -- 755 (www-data) Конфиги ядра для конкретного сайта
|   |-- errors              -- файлы спец шаблонов ошибок
|   |-- hooks               -- спец-ловушки для фрейверка. Нужны для низкоуровневого изменения поведения системы
|   |-- logs                -- 755 (www-data) сюда система пишет свои логи отладки или ошибок
|   |-- plugins             -- плагины конкретного сайта. Могут перегружать глобальные плагины системы.
|   `-- views               -- общесистемные шаблоны
|       |-- admin           -- общесистемный шаблон админ-панели
|       `-- default         -- папка шаблона сайта. Таких папок может быть много
|-- modules_vars            -- Переменные окружения модулей

На примере одного модуля можно показать общуюю струкутру

|   |-- admin               -- Окружение модуля админки
|   |   |-- dynconf         -- 755 (www-data) динамически изменяемые конфиги модуля
|   |   |-- language        -- языковые файлы модуля
|   |   |   |-- english
|   |   |   |-- russian
|   |   |   `-- ukrainian
|   |   `-- views           -- внешние шаблоны модуля.
|   |.......

И теперь папка "смотрящая в мир"

`-- www
    |-- .htaccess           -- используя mod_rewrite переопределяет вызовы на index.php
    |-- index.php           -- через этот файл проходят все вызовы и начинается работы системы
    |-- desert              -- папка с ресурсами сайта (может иметь любое имя -- определяется конфигом)
    |   |-- css             -- ...понятно из имени
    |   |-- i
    |   `-- js
    `-- rc                  -- папка ресурсов админки. Определена через конфиг темы админки. Симлинк на репазитарий.
        |-- admin           -- рекомендуется хранить ресурсы отдельных модулей в отдельных папках
        |   |-- css
        |   `-- imgs
        |-- components      -- компоненты клиентской части
        |   |-- cmenu
        |   |-- dynatree
        |   `-- jedit
        |-- css
        |-- imgs
        `-- js

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

Ваша структура может отличаться. Это не может быть идеальным решением, т.к. оно не существует. К тому же, если Вы используете на CodeIgniter, то у Вас, конечно же, масса своих нюансов. Но общий смысл моего совета в шести пунктах я описал в начале заметки.

Что бы добиться такой структуры пришлось допустить пару не желательных хаков на фреймверк, с целью переопределить некоторые маршруты поиска файлов.
Если кто-то не сумеет отыскать их самостоятельно, пишите в комментарии — распишу детальнее.


Update: Забыл подчеркнуть - все определения путей к папкам должны быть описаны в константах, ни в коем случае нельзя использовать непосредственные имена папок в коде!

4 комментария:

Анонимный комментирует...

папки языков я бы всё же сокращенно писал ru, en, uk и т.п. а то ведь потом придётся сопоставление делать url к языку, например /ru/news/press/ и т.п.

так же css, js, imgs стоит разделить на три вида папок frond, backend и common, в последней лежат общие для всех компоненты, чтобы понятно было и не дублировать

Unknown комментирует...

front и backend -- это desert и rc соответственно на схеме.
Имена папок с языками -- разумное замечание, возможно и так.
Но т.к. языками самого сайта (frontend) занимается отдельный модуль, то тут кто во что горазд так и именует.

Дмитрий Ланец комментирует...

Мне кажется следует удобней хранить модели в одном репозитории а не в каждом модуле по отдельности, так как несколько модулей могут использовать одну и туже модель, например модель product могут использовать модули best_products и product_detail.

Unknown комментирует...

А мне кажется, что best_products и product_detail это части одно и того же модуля и да, там модели лежат рядом.

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

Но если вы делаете узконаправленное приложение -- вы вольны выбирать любой удобный для вас способ взаимодействия.