Любая система работает с некоторыми настройками. Если Ваша система не имеет параметров — она деревянная.
- Ядру CMS нужны настройки;
- Настройки нужно где-то хранить;
- Настройки должны иметь удобочитаемый формат для правки, в экстренных случаях, руками;
- Кроме ядра, параметры могут иметь и каждый модуль CMS;
- Каждый имеющий параметры модуль, не должен заботиться о том, в каком виде хранятся параметры и где они хранятся;
- Ядро должно предоставлять строго определенный интерфейс для работы с параметрами любого модуля и отдельно — работу со своими параметрами (на случай модуля настройки ядра).
Спасибо, КЭП.
Основные моменты ясны. Теперь нужно обсудить решение.
Давайте определимся с форматом.
- Обычный php-файл где наполняется ассоциативный массив.
Кажется идеально — легко правиться, наглядно, очень быстро понимается сервером.
Главный минус — в такой фал проблематично писать. Нужен код для генерации подобных файлов. Задача не слишком сложная — читаем файл обычным инклудом и при записи просто разбираем массив и записываем в нужном формате.
- Красиво? Да.
- Безопасно? НЕТ!
В таком файле конфигурации можно разместить вредоносной код и он будет выполнен со всеми правами серверного приложения. Способов проникновения в такой файл много. Это могут быть атаки на не экранированные параметры или использование других ошибок, все случаи предусмотреть не получиться. Важно исключить саму возможность выполнения такого кода.
- XML
Хороший формат. Структурированное хранение информации. Вполне достаточная гибкость хранения сложных структур данных. Популярны, в конце концов, формат. - INI
Динозавр среди форматов. В нашем случае подходит плохо, т.к. он отлично справляется только с хранением двухуровневых данных. Да, можно научить его хранить и более сложные структуры. Но... Это лишнее. - Сериализация данных средствами PHP
Чтож, это вариант. PHP способен сериализировать большие объемы данных в формат удобный для него. Вы когда ни будь пытались прочитать такие данные?
Пример:
Имеем массив:
array('conf_id' => 34, 'size_mas' => array(123, 12, 34, 56));
в сериализированом виде он выглядит как:
a:2:{s:7:"conf_id";i:34;s:8:"size_mas";a:4:{i:0;i:123;i:1;i:12;i:2;i:34;i:3;i:56;}}
Вам легко такое читать и изменять? Мне — нет.
- Свои форматы
Это хорошо. Если Вы имеете свою библиотеку позволяющую сохранять в файлы и читать сложные структуры данных. И Вас устраивает вид в котором они хранятся — это Ваш выбор. - YAML
Этот формат я выбрал для себя. Меня устраивает то, как данные выглядят в файле.
Тот же массив из примера:conf_id: 34 size_mas: - 123 - 12 - 34 - 56
Для реализации работы с форматом YAML я не стал изобретать велосипед, решив взять уже готовое решение. На официальном сайте Прямо на главной странице приводиться масса ссылок на реализации для различных языков программирования. Для себя я выбрал реализацию под названием spyc.
Класс для работы с параметрами в моем решении представляет из себя класс с набором статических методов:
- load($module, $folder = null, $file = null) — загрузка
$module — имя модуля чьи параметры мы хотим прочитать или константа чтения параметров ядра (например, «_SYSTEM_»).
$folder — имя папки хранения файла конфигурации. Может использоваться для отделения специфических настроек модуля.
$file — имя файла для специфических параметров. - save($module, $array, $folder = null, $file = null) — сохранение
единственное отличие от load — второй параметр, принимающий массив с параметрами. - toString($data) — возвращает текст сериализованых данных $data
- fromString($str) — обратная операция, из текста в массив.
Что именно использовать для параметров — массив или объект — решать Вам. Не сложно реализовать и обработку объектов. Для простоты описания я выбрал простые массивы.
Таким образом, save и load работают с именем модуля, что указывает на то, где искать файл параметров.
В предыдущей заметке я описал свою файловую структуру и по ней путь к файлу строиться как mods_vars/$module/dynconf/[$folder/][$file] или с использованием стандартного имени conf.yaml.
В результате, мы получаем возможность вызвать чтение или сохранение параметров из любой точки системы. Т.к. класс работы с параметрами инициализируется в ядре системы, значит он доступен всюду в системе.
Здесь, нужно определиться с именем такого класса. Имя Config нам не доступно, т.к. совпадает с классом фреймверка. Да, базовый класс фреймверка называеться CI_Config, но я бы советовал выбрать другое имя. И вот еще что, его можно было бы вписать в расширение базового класса через механизм «MY_class», но я не стал этого делать, т.к. в моем понимании это отчасти противоречит идеологии фреймверка в связке с ядром. Я предпочел сделать отдельный класс с именем Confman. Теперь вызов параметров модуля admin у меня выглядет как
$conf = Confman::load('admin');
Методы toString и fromString Вам могут пригодиться позже, например для записи в базу некоторой структурированной информации для которой не стали делать разборку по полям, но нужно сохранить структуру и оставить её читаемой в ручном режиме.
Методы позволяющие заполнить поля в классе из конфига я решил исключить. Но если кому-то это покажется нужным, то знание языка Вам в помощь.
Если я что-то упустил — добро пожаловать в комментарии, буду рад ответить на вопросы и дополнить статью, если я о чем-то не вспомнил.
2 комментария:
Было бы интересно посмотреть на реализацию Вашего класса на примере.
Вы не знаете как написать свой?
Мне кажется, это простая задача.
К тому же, моя реализация будет опираться на мой код всей остальной системы.
А цель данных заметок - высказать свое виденье общей схемы работы. Я не вижу смысла поэтапно выкладывать здесь код всего движка. Если рассматриваемый случай потребует, для объяснения, привести пример кода - я приведу пример, но при этом постараюсь абстрагироваться от зависимостей своей реализации.
Мой код, в течении ближайшего времени появиться в свободном доступе, тогда, скорее всего, я начну ссылаться на эти исходники.
Еще раз повторюсь - этот блог не ставит перед собой цель описать конкретно мой движек. Это в первую очередь размышления на тему Как решать спорные моменты при создании собственной системы управления контентом.
Отправить комментарий