Основные принципы устройства платформы
Внимание: платформа TAO построена с широким использованием объектно-ориентированного программирования, поэтому мы предполагаем, что читатель данных статей в достаточной мере разбирается в этой теме.
Платформа TAO работает по принципу перенаправления всех запросов (кроме статических файлов) на один файл - обработчик запросов - www/index.php. Для этого используется механизм RewriteEngine, предоставляемый веб-сервером Apache. Настройки перенаправления находятся в стандартном файле .htaccess:
RewriteEngine on RewriteRule ^index.php - [L] RewriteRule !\.(js|ico|gif|jpg|jpeg|png|css|chm|doc|xls|zip|pdf|txt)$ /index.php
По умолчанию невозможно вызвать никакой другой PHP-файл даже если он физически существует на сервере. При желании правила перенаправления можно менять как угодно, главное - чтобы нужные запросы направлялись на index.php
Заглянем в файл www/index.php. Вот типичное его содержимое после установки (с комментариями):
<?php // Установка нужной локали setlocale(LC_ALL,'ru_RU.UTF-8'); // Подключение ядра библиотеки include('../tao/lib/Core.php'); // Инициализация загруженного ядра Core::initialize(); // Загрузка модуля CMS Core::load('CMS'); // Запуск CMS CMS::Run();
Кроме этого там могут быть строки, проверяющие наличие инсталляционного пакета:
if (is_file('./install/install.php')) { include('./install/install.php'); die; }
Если они есть, то их лучше сразу удалить, чтобы не мешались.
Ядро библиотеки - это единственный модуль, который загружается через функцию include() и вручную инициализируется вызовом Core::initialize(). Для всех остальных модулей есть механизм загрузки через вызов Core::load(<Имя.Модуля>). Кроме index.php функция include мало где используется. Она может встречаться в шаблонах (когда один шаблон включает в себя другой), но почти весь PHP-код должен быть оформлен в виде модулей.
Модули
Модуль в TAO реализуется в виде специальным образом именованного PHP-файла, в котором находится по крайней мере один специальным образом оформленный класс. Имя модуля - иерархическое, состоит из частей, разделенных точкой. Например:
- DB - модуль, предствляющий API для работы с базами данных
- DB.Adapter - модуль, определяющий интерфейс для адаптеров БД
- DB.Adapter.MySQL - модуль, реализующий конкретный адаптер (в данном случае - для работы с MySQL)
Модуль загружается при помощи вызова Core::load(<Имя.Модуля>). При этом загрузчик пытается найти и загрузить файл, вычислив имя и путь к файлу, исходя из имени модуля.
PHP-файл, реализующий модуль, должен иметь расширение "php" и имя, повторяющее последнюю часть имени модуля (после последней точки). Путь к файлу также зависит от имени модуля и повторяет его иерархией каталогов. Например, модуль DB.Adapter.MySQL реализуется файлом tao/lib/DB/Adapter/MySQL.php. При этом обратите внимание, что данный путь считается от каталога tao/lib, но это не для всех модулей. Стартовая точка вычисления пути к модулю зависит от первой части имени модуля. По умолчанию сделано следующим образом:
1. Модули, имя которых начинается с "App" находятся в каталоге app/lib. При этом для иерахически подчиненных модулей слово App не учитывается при вычислении пути. Например:
- Модуль App ищется в файле app/lib/App.php
- Модуль App.Utils ищется в файле app/lib/Utils.php
- Модуль App.Utils.Images ищется в файле app/lib/Utils/Images.php
В таких модулях следует размещать функционал конкретного веб-приложения кроме того функционала, который можно объединить и вынести в компоненты.
2. Модули, имя которых начинается с "Component" находятся в каталоге app/components. При этом слово Component не учитывается при вычислении пути. Например:
- Модуль Component.Catalog ищется в файле app/components/Catalog.php
- Модуль Component.Catalog.DB ищется в файле app/components/Catalog/DB.php
- Модуль Component.Catalog.DB.Schema ищется в файле app/components/Catalog/DB/Schema.php
В таких модулях размещается функционал компонентов. В структуре компонентов также возможны более сложные схемы вычисления пути к файлу модуля, однако, это - тема для отдельной статьи.
3. Все остальные модули ищутся в каталоге tao/lib. При этом от имени ничего не отрезается, пути к файлам полностью соответсвуют именам модулей. Эти модули относятся к ядру TAO и не предполагаются к какой-либо модификации при создании веб-приложения. Любые сделанные вами изменения внутри tao/lib будут неизбежно стерты при обновлении ядра.
Устройство и загрузка модуля
В PHP-файле модуля обязательно должен присутствовать класс, реализующий интерфейс Core_ModuleInterface и имеющий имя, повторяющее имя модуля, в котором точки заменены на знаки подчеркивания. Также в этом файле могут (но не обязательно) находиться и другие классы, необходимые для функционирования модуля.
Таким образом, минимальный файл модуля App.Utils будет выглядеть так:
<?php class App_Utils implements Core_ModuleInterface { }
Модуль загружается функцией Core::load(). Она может быть вызвана в любом месте и сработает только один раз. Если такой модуль уже был когда-то загружен, то во второй и последующий вызовы ничего не произойдет. Это удобно тем, что при необходимости использовать какую-либо функциональность можно, не беспокоясь, прямо на ходу подключить нужный модуль и использовать его.
Например:
// Если есть картинка, то ее нужно трансформировать if ($image_filename) { // Загружаем модуль Core::load('CMS.Images'); // Используем модуль $image = CMS_Images::Image($image_filename); // ...... // какие-то действия с картинкой // ...... $image->save(); }
Инициализация и конфигурирование модуля
Иногда (впрочем, довольно часто) при загрузке модуля требуется выполнить какие-то действия. Будем называть их инициализацией модуля. Для этой цели в классе модуля предусмотрена статическая функция initialize(). Она не обязательна, но если присутствует, то будет запущена при первом вызове Core::load().
Например:
class App_Utils implements Core_ModuleInterface { public static function initialize() { // Какие-то действия } }
Функция initialize может также принимать конфигурационные параметры в виде массива. Это сделано для того, чтобы иметь возможность как-то сконфигурировать модуль, в код которого по той или иной причине нельзя вмешиваться (например, в модуль ядра).
Вот так, например, сделано в модуле CMS.Images. По умолчанию все JPEG-изображения сохраняются с параметром качества 80. Но должна быть возможность изменить этот параметр без вмешательства в код модуля. Поэтому все устроено следующим образом:
class CMS_Images implements Core_ModuleInterface { protected static $jpeg_quality = 80; public static function initialize($config=array()) { foreach($config as $key => $value) { self::$$key = $value; } } }
Теперь заглянем в конфигурационный файл app/config/modules.php. Изначально там нет ни одного параметра, только для примера заведен раздел для конфигурирования модуля CMS:
<?php return array( 'CMS' => array( ), );
Наша задача - добавить еще один раздел для конфигурирования модуля CMS.Images, представляющий собой массив, в котором в виде ключ => значение идут необходимые конфигурационные параметры:
<?php return array( 'CMS' => array( ), 'CMS.Images' => array( 'jpeg_quality' => 95, ), );
Созданный вами массив будет передан в функцию initialize.
Что дальше?
Теперь, когда вы узнали об устройстве модулей, поговорим о компонентах.