Основные принципы устройства платформы

Внимание: платформа 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.

Что дальше?

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

Метки: Азы
29.11.2013
Все статьи