Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Moodle

Оригинал: Moodle
Автор: Tim Hunt
Перевод: А.Панин

13.4. Генерация результирующего документа

Процесс генерации результирующего документа в большей степени зависит от двух глобальных объектов.

Строка 8: Глобальная переменная $PAGE

$PAGE->set_context($context);                                 // 8

Переменная $PAGE хранит информацию о странице, которая должна быть сгенерирована. Эта информации впоследствии доступна для кода, генерирующего результирующий HTML-документ. Для работы этого сценария требуется явное указание используемого контекста. (В других случаях контекст может быть установлен автоматически с помощью функции require_login.) Строка URL для этой страницы также должна быть явно задана. Это может показаться избыточным, но обоснование требования этих данных заключается в том, что вы можете перейти на определенную страницу, используя любое количество различных строк URL, но строка URL, передаваемая функции set_url должна быть канонической строкой URL для страницы - качественной постоянной ссылкой, если вам угодно. Заголовок страницы также устанавливается. Этот процесс заканчивается генерацией элемента head документа HTML.

Строка 9: Строка URL приложения Moodle

$PAGE->set_url(new moodle_url('/local/greet/index.php'),
        array('name' => $name));                              // 9

Я хотел бы обратить внимание на этот замечательный небольшой вспомогательный класс, который позволяет значительно упростить манипуляции со строками URL. Отдельно следует вспомнить о том, что функция add_to_log, вызванная выше, не использует этот вспомогательный класс. В самом деле, API журналирования не может принимать объекты moodle_url. Этот тип несовместимости является типичным признаком значительного возраста кодовой базы приложения, такого, как у кодовой базы приложения Moodle.

Строка 10: Интернационализация

$PAGE->set_title(get_string('welcome', 'local_greet'));       // 10

Приложение Moodle использует свою собственную систему для перевода интерфейса на любой из языков. На сегодняшний день может быть доступно большое количество библиотек интернационализации для языка PHP, но в 2002 году, когда приложение было впервые реализовано, не было доступно ни одной подходящей библиотеки. Система формируется вокруг функции get_string. Строки идентифицируются с помощью ключа и названия расширения в формате Frankenstyle. Как можно увидеть в строке 12, возможно преобразовать значения в строку. (Множества значений обрабатываются с использованием массивов объектов языка PHP.)

Поиск строк осуществляется в языковых файлах, содержащих простые массивы языка PHP. Ниже приведен языковой файл local/greet/lang/en/local_greet.php для нашего расширения:
<?php
$string['greet:begreeted'] = 'Be greeted by the hello world example';
$string['welcome'] = 'Welcome';
$string['greet'] = 'Hello, {$a}!';
$string['pluginname'] = 'Hello world example';

Следует отметить то, что наряду с двумя строками, используемыми в нашем сценарии, в файле также присутствуют строки для указания названия возможности и названия расширения, которые отобразятся в пользовательском интерфейсе.

Различные языки идентифицируются с помощью двухбуквенных кодов стран (в данном случае en). Языковые пакеты могут происходить от других языковых пакетов. Например, fr_ca (французский канадский) языковой пакет декларирует fr (французский) в качестве родительского языка и, таким образом, задает только те строки, которые отличаются от строк французского языка. Так как разработка приложения Moodle началась в Австралии, код en относится к британскому английскому языку, а языковой пакет en_us (американский английский) происходит от него.

Снова следует упомянуть о том, что простой API на основе функции get_string для разработчиков расширений скрывает большую часть сложностей, включая установление языка (который может зависеть от действующих пользовательских настроек или настроек определенного курса, который изучается в данный момент) и поиск среди всех языковых пакетов и родительских языковых пакетов с целью получения строки.

Создание файлов языковых пакетов и координация переводов осуществляется с помощью ресурса http://lang.moodle.org/, который использует приложение Moodle со специальным расширением (local_amos). Этот ресурс использует систему контроля версий Git и базу данных в качестве системы для хранения языковых файлов вместе с полной историей версий.

Строка 11: Начало операции вывода страницы

echo $OUTPUT->header();                                       // 11

Это еще одна безобидно выглядящая строка, которая делает гораздо больше, чем кажется. Дело в том, что перед выполнением любой операции вывода страницы должна быть выбрана подходящая тема (оболочка). Этот процесс может зависеть от комбинации контекста страницы и настроек пользователя. Значение переменной $PAGE->context, однако, было установлено в строке 8, поэтому глобальная переменная $OUTPUT не будет инициализирована в начале сценария. В общем случае, решение этой проблемы заключается в использовании особенности языка PHP для создания соответствующего объекта $OUTPUT на основе информации, получаемой из переменной $PAGE в первый момент вызова любого метода для вывода страницы.

Еще одной важной особенностью является то, что каждая страница приложения Moodle может содержать блоки (blocks). Эти элементы являются дополнительными настраиваемыми частями содержимого страницы, которые обычно выводятся слева или справа от основного содержимого страницы. (Они являются своего рода расширениями.) Снова следует упомянуть о том, что определенный набор выводимых блоков зависит от гибко изменяемых параметров (которые могут контролироваться администратором) контекста страницы и других аспектов идентичности страницы. Следовательно, следующим шагом подготовки к выводу страницы является вызов функции $PAGE->blocks->load_blocks().

Как только вся необходимая информация обработана, расширение тем (которое в полной степени контролирует внешний вид страницы) вызывается для генерации страницы, включая стандартные заголовочные и завершающие области страницы, если это необходимо. Этот вызов также отвечает за добавление данных блоков в необходимое место результирующего документа формата HTML. В середине выводимой страницы должен находиться тэг div, в котором будет находиться специфическое содержимое этой страницы. После генерации документа в формате HTML он разделяется на две части по тегу div, находящемуся перед началом основного содержимого. Первая часть возвращается, а вторая - сохраняется для последующего возврата с помощью функции $OUTPUT->footer().

Строка 12: Операция вывода основной части страницы

echo $OUTPUT->box(get_string('greet', 'local_greet',
        format_string($name)));                               // 12

В этой строке производится вывод основной части страницы. В данном случае просто выводится сообщение приветствия. Приветствие, повторюсь, является локализованной строкой, в данном случае со значением, подставляемым в предназначенное для него поле. Основной объект вывода $OUTPUT предоставляет множество таких полезных методов, как box для описания требуемых выводимых элементов с помощью высокоуровневых директив. Различные темы могут контролировать то, какой именно код HTML будет использован для вывода сообщения.

Данные, изначально полученные из переменной пользователя ($name) выводятся после обработки с помощью функции format_string. Это еще одно мероприятие для защиты от XSS-атак. Эта функция также позволяет пользователю применять фильтры текста (другой тип расширения). Примером фильтра может быть фильтр LaTeX, который заменяет такие входные данные, как $$x + 1$$ на изображение математического действия. Я упомяну, но не буду подробно описывать то, что на самом деле существуют три различных функции (s, format_string и format_text), применяемые в зависимости от определенного выводимого типа содержимого страницы.

Строка 13: Завершение операции вывода страницы

echo $OUTPUT->footer();                                       // 13

Наконец осуществляется вывод завершающей части страницы. Этот пример не иллюстрирует данную операцию, но приложение Moodle отслеживает все сценарии на языке JavaScript, необходимые для функционирования страницы, и выводит все необходимые тэги для подключения сценариев в завершающей части страницы. Это стандартная и разумная практика. Она позволяет пользователям видеть страницу без ожидания загрузки всех сценариев на языке JavaScript. Разработчик должен подключать сценарии на языке JavaScript с помощью таких вызовов API, как $PAGE->requires->js('/local/greet/cooleffect.js').

Приводит ли эта практика к смешению логики и выводимых данных

Очевидно, что размещение выводимого кода в файле сценария index.php даже при высоком уровне абстракции ограничивает гибкость управления выводимыми данными с помощью тем. Это является еще одним признаком значительного возраста кодовой базы приложения Moodle. Глобальная переменная $OUTPUT была представлена в 2010 году как переходный этап в рамках мероприятий по отказу от устаревшего кода, в котором функции вывода и управления содержимым страницы были размещены в одном файле и перехода к архитектуре, в которой весь код вывода страницы был корректно отделен. Это также иллюстрирует неудачный способ генерации страницы, ее разделения на две части, после чего выводимые сценарием данные могут быть размещены между заголовочной и завершающей областью страницы. Как только код вывода страницы был выделен из описанного сценария и перенесен в сценарий, который называется сценарием вывода страницы приложения Moodle, темы получили возможность осуществлять полную (или частичную) замену функций кода вывода страницы для рассматриваемого сценария.

Небольшой рефакторинг может позволить переместить код вывода страницы из сценария index.php в сценарий вывода страницы. Завершающие строки сценария index.php (строки с 11 по 13) изменятся на:
$output = $PAGE->get_renderer('local_greet');
echo $output->greeting_page($name);
и появится новый файл local/greet/renderer.php:
<?php
class local_greet_renderer extends plugin_renderer_base {
    public function greeting_page($name) {
        $output = '';
        $output .= $this->header();
        $output .= $this->box(get_string('greet', 'local_greet', $name));
        $output .= $this->footer();
        return $output;
    }
}

Если теме необходимо полностью изменить этот вывод, она может объявить подкласс этого класса, в котором будет повторно объявлен метод greeting_page. Функция $PAGE->get_renderer() устанавливает подходящий класс вывода страницы для ее вывода в зависимости от используемой темы. Следовательно, код вывода (показа) страницы полностью отделен от кода управления из файла index.php и проведено усовершенствование расширения с уровня использования устаревшего кода Moodle до уровня использования архитектуры MVC ("модель-представление-поведение" - "model-view-controller").


Далее: Абстракция для работы с базой данных