Представления
Содержание
Введение
Представления отвечают за создание вывода. Они обрабатывают всё, начиная от:
макета страниц
фрагментов выводимого контента (например, футер или панель инструментов)
отдельных ссылок и полей ввода форм.
изображений, js и css, необходимых для вашей веб-страницы
Использование представлений
На самом базовом уровне представления по умолчанию — это просто файлы PHP с фрагментами HTML:
<h1>Hello, World!</h1>
Предполагая, что это представление расположено в /views/default/hello.php, мы можем вывести его так:
echo elgg_view('hello');
Для вашего удобства в Elgg по умолчанию поставляется довольно много представлений. Чтобы всё было управляемым, они организованы в подкаталоги. Elgg справляется с этой ситуацией довольно хорошо. Например, наше простое представление может находиться в /views/default/hello/world.php, в этом случае оно будет вызываться так:
echo elgg_view('hello/world');
Имя представления просто отражает расположение представления в директории views.
Представления как шаблоны
Вы можете передать произвольные данные в представление через массив $vars. Наше представление hello/world может быть модифицировано для приёма переменной так:
<h1>Hello, <?= $vars['name']; ?>!</h1>
В этом случае мы можем передать произвольный параметр name в представление так:
echo elgg_view('hello/world', ['name' => 'World']);
что даст следующий вывод:
<h1>Hello, World!</h1>
Предупреждение
Представления по умолчанию не выполняют никакой автоматической санитизации вывода. Вы сами отвечаете за правильную санитизацию для предотвращения атак XSS и тому подобного.
Представления как кешируемые ресурсы
Как упоминалось ранее, представления могут содержать JS, CSS или даже изображения.
Представления ресурсов должны соответствовать определённым требованиям:
Они не должны принимать какие-либо параметры
$varsОни не должны изменять свой вывод на основе глобального состояния, такого как
кто авторизован
время суток
Они должны содержать допустимое расширение файла
Плохо:
my/cool/templateХорошо:
my/cool/template.html
Например, предположим, вы хотите загрузить какой-то CSS на страницу. Вы можете определить представление mystyles.css, которое будет выглядеть так:
/* /views/default/mystyles.css */
.mystyles-foo {
background: red;
}
Примечание
Опустите завершающее «.php» в имени файла, и Elgg автоматически распознает представление как кешируемое.
Чтобы получить URL к этому файлу, используйте elgg_get_simplecache_url:
// Returns "https://mysite.com/.../289124335/default/mystyles.css
elgg_get_simplecache_url('mystyles.css');
Elgg автоматически добавляет магические числа, которые вы там видите, для обхода кеша и устанавливает долгосрочные заголовки expires на возвращаемый файл.
Предупреждение
Elgg может решить изменить расположение или структуру возвращаемого URL в будущем релизе по любой причине, и числа для обхода кеша меняются каждый раз при очистке кешей Elgg, поэтому точный URL не является стабильным по замыслу.
Имея это в виду, вот несколько анти-паттернов, которых следует избегать:
Не полагайтесь на точную структуру/расположение этого URL
Не пытайтесь генерировать URL самостоятельно
Не храните возвращаемые URL в базе данных
На странице, где вы хотите загрузить css, вызовите:
elgg_require_css('mystyles');
Представления и сторонние ресурсы
Лучший способ обслуживать сторонние ресурсы — через представления. Однако вместо ручного копирования/вставки ресурсов в нужное место в /views/*, вы можете сопоставить ресурсы с системой представлений через ключ "views" в конфигурационном файле elgg-plugin.php вашего плагина.
Значение views должно быть двумерным массивом. Первый уровень сопоставляет viewtype со списком сопоставлений представлений. Вторичные списки сопоставляют имена представлений с путями к файлам, абсолютными или относительными к корневой директории Elgg.
Если вы добавляете свои ресурсы в систему контроля версий, укажите на них так:
<?php // mod/example/elgg-plugin.php
return [
// view mappings
'views' => [
// viewtype
'default' => [
// view => /path/from/filesystem/root
'js/jquery-ui.js' => __DIR__ . '/node_modules/components-jqueryui/jquery-ui.min.js',
],
],
];
Чтобы указать на ресурсы, установленные через composer, используйте пути относительно корня установки, опуская начальный слеш:
<?php // mod/example/elgg-plugin.php
return [
'views' => [
'default' => [
// view => path/from/install/root
'js/jquery-ui.js' => 'vendor/npm-asset/components-jqueryui/jquery-ui.min.js',
],
],
];
Ядро Elgg широко использует эту функцию, хотя значение возвращается непосредственно из /engine/views.php.
Примечание
Вам не обязательно использовать NPM, Composer Asset Plugin или любой другой скрипт для управления ресурсами вашего плагина, но мы настоятельно рекомендуем использовать какой-либо менеджер пакетов, потому что это значительно упрощает обновление.
Указание дополнительных директорий представлений
В elgg-plugin.php вы также можете указать директории для сканирования на предмет представлений. Просто укажите префикс имени представления, заканчивающийся на /, и путь к директории (как выше).
<?php // mod/file/elgg-plugin.php
return [
'views' => [
'default' => [
'file/icon/' => __DIR__ . '/graphics/icons',
],
],
];
С указанным выше, файлы, найденные в папке icons, будут интерпретированы как представления. Например, представление file/icon/general.gif будет создано и сопоставлено с mod/file/graphics/icons/general.gif.
Примечание
Это полностью рекурсивное сканирование. Все найденные файлы будут добавлены в систему представлений.
Несколько путей могут использовать один и тот же префикс, просто передайте массив путей:
<?php // mod/file/elgg-plugin.php
return [
'views' => [
'default' => [
'file/icon/' => [
__DIR__ . '/graphics/icons',
__DIR__ . '/more_icons', // processed 2nd (may override)
],
],
],
];
Типы представлений
Вы можете задаться вопросом: «Почему /views/default/hello/world.php вместо просто /views/hello/world.php?».
Подкаталог в /views определяет viewtype представлений ниже него. Viewtype обычно соответствует формату вывода представлений.
По умолчанию предполагается, что viewtype — это HTML и другие статические ресурсы, необходимые для отображения адаптивной веб-страницы в десктопном или мобильном браузере, но это также может быть:
RSS
ATOM
JSON
HTML, оптимизированный для мобильных устройств
HTML, оптимизированный для ТВ
Любое количество других форматов данных
Вы можете заставить Elgg использовать определённый viewtype для отрисовки страницы, установив входную переменную view так: https://mysite.com/?view=rss.
Вы также можете написать плагин для автоматической установки этого с помощью функции elgg_set_viewtype(). Например, ваш плагин может определить, что страница была открыта с браузерной строкой iPhone, и установить viewtype в iphone, вызвав:
elgg_set_viewtype('iphone');
Плагин, предположительно, также предоставит набор представлений, оптимизированных для этих устройств.
Изменение представлений через плагины
Без изменения ядра Elgg, Elgg предоставляет несколько способов настройки практически всего вывода:
Вы можете переопределить представление, полностью изменив файл, используемый для его отрисовки.
Вы можете расширить представление, добавив в начало или конец вывод другого представления.
Вы можете изменить входные данные представления через событие.
Вы можете изменить вывод представления через событие.
Переопределение представлений
Представления в директориях плагинов всегда переопределяют представления в директории ядра; однако, когда плагины переопределяют представления других плагинов, более поздние плагины имеют приоритет.
Например, если мы хотим настроить представление hello/world для использования h2 вместо h1, мы можем создать файл в /mod/example/views/default/hello/world.php так:
<h2>Hello, <?= $vars['name']; ?></h2>
Примечание
При рассмотрении долгосрочного обслуживания, переопределение представлений в ядре и встроенных плагинах имеет свою цену: обновления могут приносить изменения в представлениях, и если вы их переопределили, вы не получите эти изменения.
Возможно, вместо этого вы захотите изменить входные данные или вывод представления через события.
Примечание
Elgg кеширует расположения представлений. Это означает, что вы должны отключить системный кеш при разработке с использованием представлений. При установке изменений в производственную среду вы должны очистить кеши.
Расширение представлений
Могут быть и другие ситуации, когда вы не хотите переопределять всё представление, а просто хотите добавить в начало или конец немного контента. В Elgg это называется расширением представления.
Например, вместо переопределения представления hello/world, мы можем расширить его так:
elgg_extend_view('hello/world', 'hello/greeting');
Если содержимое /views/default/hello/greeting.php:
<h2>How are you today?</h2>
Тогда каждый раз при вызове elgg_view('hello/world'); мы получим:
<h1>Hello, World!</h1>
<h2>How are you today?</h2>
Вы можете добавить представления в начало, передав значение в третий параметр, которое меньше 500:
// appends 'hello/greeting' to every occurrence of 'hello/world'
elgg_extend_view('hello/world', 'hello/greeting');
// prepends 'hello/greeting' to every occurrence of 'hello/world'
elgg_extend_view('hello/world', 'hello/greeting', 450);
Все расширения представлений должны быть зарегистрированы в файле elgg-plugin.php вашего плагина.
Изменение входных данных представления
Может быть полезно изменить массив $vars представления перед его отрисовкой.
Перед каждой отрисовкой представления массив $vars фильтруется событием event ["view_vars", $view_name]. Каждая зарегистрированная функция-обработчик получает следующие аргументы:
$event— строка"view_vars"$view_name— имя отрисовываемого представления (первый аргумент, переданный вelgg_view())$returnvalue— изменённый массив$vars$params— массив, содержащий:vars— исходный массив$vars, без измененийview— имя представленияviewtype— отрисовываемый viewtype
Пример изменения входных данных представления
Здесь мы изменим лимит пагинации по умолчанию для представления комментариев:
elgg_register_event_handler('view_vars', 'page/elements/comments', 'myplugin_alter_comments_limit');
function myplugin_alter_comments_limit(\Elgg\Event $event) {
$vars = $event->getValue();
// only 10 comments per page
$vars['limit'] = elgg_extract('limit', $vars, 10);
return $vars;
}
Изменение вывода представления
Иногда предпочтительнее изменить вывод представления вместо его переопределения.
Вывод каждого представления проходит через событие event ["view", $view_name] перед возвратом из elgg_view(). Каждая зарегистрированная функция-обработчик получает следующие аргументы:
$event— строка"view"$view_name— имя отрисовываемого представления (первый аргумент, переданный вelgg_view())$result— изменённый вывод представления$params— массив, содержащий:viewtype— отрисовываемый viewtype
Чтобы изменить вывод представления, обработчику достаточно изменить $returnvalue и вернуть новую строку.
Пример изменения вывода представления
Здесь мы устраним хлебные крошки, которые не содержат хотя бы одной ссылки.
elgg_register_event_handler('view', 'navigation/breadcrumbs', 'myplugin_alter_breadcrumb');
function myplugin_alter_breadcrumb($event, $type, $returnvalue, $params) {
// we only want to alter when viewtype is "default"
if ($params['viewtype'] !== 'default') {
return $returnvalue;
}
// output nothing if the content doesn't have a single link
if (false === elgg_strpos($returnvalue, '<a ')) {
return '';
}
// returning nothing means "don't alter the returnvalue"
}
Полная замена вывода представления
Вы можете заранее установить вывод представления, установив $vars['__view_output']. Значение будет возвращено как строка. Расширения представлений не будут использоваться, и событие view не будет вызвано.
elgg_register_event_handler('view_vars', 'navigation/breadcrumbs', 'myplugin_no_page_breadcrumbs');
function myplugin_no_page_breadcrumbs(\Elgg\Event $event) {
if (elgg_in_context('pages')) {
return ['__view_output' => ""];
}
}
Примечание
Для удобства вы также можете использовать уже существующий обратный вызов события по умолчанию для предотвращения вывода \Elgg\Values::preventViewOutput
Отображение сущностей
Если вы не знаете, что такое сущность, сначала ознакомьтесь с этой страницей.
Следующий код автоматически отобразит сущность в $entity:
echo elgg_view_entity($entity);
Как вы знаете из введения в модель данных, все сущности имеют тип (object, site, user или group) и, опционально, подтип (который может быть чем угодно — „blog“, „forumpost“, „banana“).
elgg_view_entity автоматически поищет представление с именем type/subtype; если подтипа нет, оно поищет type/type. Если это не сработает, перед полным отказом оно попробует type/default.
RSS-ленты в Elgg обычно работают путём вывода представления object/default в viewtype „rss“.
Например, представление для отображения поста блога может быть object/blog. Представление для отображения пользователя — user/default.
Полные и частичные представления сущностей
elgg_view_entity на самом деле имеет несколько параметров, хотя требуется только самый первый. Первые три:
$entity— сущность для отображения$viewtype— viewtype для отображения (по умолчанию используется текущий, но его можно принудительно задать — например, для отображения фрагмента RSS внутри HTML-страницы)$full_view— отображать ли полную версию сущности. (По умолчаниюtrue.)
Этот последний параметр передаётся в представление как $vars['full_view']. Вам решать, что с ним делать; обычное поведение — отображать комментарии и подобную информацию, только если установлено значение true.
Списки сущностей
Затем это используется в предоставленных функциях списков. Чтобы автоматически отобразить список постов блога (см. полное руководство), вы можете вызвать:
echo elgg_list_entities([
'type' => 'object',
'subtype' => 'blog',
]);
Эта функция проверяет, есть ли сущности; если есть, сначала отображается представление navigation/pagination для отображения способа перехода со страницы на страницу. Затем она многократно вызывает elgg_view_entity для каждой сущности перед возвратом результата.
Обратите внимание, что elgg_list_entities позволяет URL устанавливать опции limit и offset, поэтому установите их явно, если вам нужны определённые значения (например, если вы не используете это для пагинации).
Elgg знает, что может автоматически предоставлять RSS-ленту на страницах, использующих elgg_list_entities. Он инициализирует событие ["head","page"] (которое используется заголовком) для обеспечения автообнаружения RSS, поэтому вы можете видеть оранжевую иконку RSS на этих страницах в некоторых браузерах.
Списки сущностей по умолчанию будут пытаться загрузить владельцев сущностей и владельцев контейнеров. Если вы хотите предотвратить это, вы можете отключить это.
echo elgg_list_entities([
'type' => 'object',
'subtype' => 'blog',
// disable owner preloading
'preload_owners' => false,
]);
См. также эту справочную информацию о базе данных Elgg.
Нет результатов
Если вы хотите показать сообщение, когда список не содержит элементов для отображения, вы можете передать сообщение no_results или true для сообщения по умолчанию. Если вы хотите ещё больше контроля над сообщением no_results, вы также можете передать Closure (анонимную функцию).
echo elgg_list_entities([
'type' => 'object',
'subtype' => 'blog',
'no_results' => true,
]);
Если вы передадите 'no_results' => true, система проверит, есть ли языковой ключ list:<type>:<subtype>:no_results, если вы хотите иметь немного более специфичный текст для отсутствия результатов (например: Блоги не найдены). Если конкретный языковой ключ не найден, используется elgg_echo('notfound') по умолчанию.
Отрисовка списка с альтернативным представлением
Вы можете определить альтернативное представление для отрисовки элементов списка, используя параметр 'item_view'.
В некоторых случаях представления сущностей по умолчанию могут не подходить для ваших нужд. Использование item_view позволяет настроить внешний вид, сохраняя при этом пагинацию, HTML-разметку списка и т.д.
Рассмотрим два примера:
echo elgg_list_entities([
'type' => 'group',
'relationship' => 'member',
'relationship_guid' => elgg_get_logged_in_user_guid(),
'inverse_relationship' => false,
'full_view' => false,
]);
echo elgg_list_entities([
'type' => 'group',
'relationship' => 'invited',
'relationship_guid' => (int) $user_guid,
'inverse_relationship' => true,
'item_view' => 'group/format/invitationrequest',
]);
В первом примере мы отображаем список групп, участником которых является пользователь, используя представление группы по умолчанию. Во втором примере мы хотим отобразить список групп, в которые был приглашён пользователь.
Поскольку приглашения не являются сущностями, у них нет собственных представлений, и их нельзя вывести с помощью elgg_list_*. Мы предоставляем альтернативное представление элемента, которое будет использовать сущность группы для отображения приглашения, содержащего имя группы и кнопки для доступа или отклонения приглашения.
Отрисовка списка в виде таблицы
Начиная с версии 2.3 вы можете отрисовывать списки в виде таблиц. Установите $options['list_type'] = 'table' и предоставьте массив объектов TableColumn как $options['columns']. Сервис elgg()->table_columns предоставляет несколько методов для создания объектов колонок на основе существующих представлений (таких как page/components/column/*), свойств или методов.
В этом примере мы выводим последние объекты my_plugin в таблице из 3 колонок: иконка сущности, отображаемое имя и дружественный формат времени.
echo elgg_list_entities([
'type' => 'object',
'subtype' => 'my_plugin',
'list_type' => 'table',
'columns' => [
elgg()->table_columns->icon(),
elgg()->table_columns->getDisplayName(),
elgg()->table_columns->time_created(null, [
'format' => 'friendly',
]),
],
]);
См. класс Elgg\Views\TableColumn\ColumnFactory для получения более подробной информации о том, как указываются и отрисовываются колонки. Вы можете добавить или переопределить методы elgg()->table_columns различными способами, на основе представлений, свойств/методов элементов или заданных функций.
Иконки
Elgg поддерживает два вида иконок: общие иконки для помощи со стилями (например, показать иконку удаления) и иконки сущностей (например, аватар пользователя).
Общие иконки
Начиная с Elgg 2.0 общие иконки основаны на библиотеке FontAwesome. Вы можете получить любую из поддерживаемых иконок, вызвав elgg_view_icon($icon_name, $vars);, где:
$icon_name— имя FontAwesome (безfa-), напримерuser$vars— необязательный параметр, например, вы можете установить дополнительный класс
elgg_view_icon() вызывает представление output/icon с заданным именем иконки и выводит все правильные классы для отрисовки иконки FontAwesome. Если вы хотите заменить одну иконку на другую, вы можете написать событие view_vars, output/icon для замены имени иконки на вашу замену.
Для обратной совместимости некоторые старые имена иконок Elgg переводятся в соответствующую иконку FontAwesome.
Иконки сущностей
Чтобы просмотреть иконку, принадлежащую сущности, вызовите elgg_view_entity_icon($entity, $size, $vars);, где:
$entity— этоElggEntity, для которой вы хотите показать иконку$size— запрошенный размер. По умолчанию Elgg поддерживаетlarge,medium,small,tinyиtopbar(также доступенmaster, но не используйте его)$vars— для передачи дополнительной информации в представление иконки
elgg_view_entity_icon() вызывает представление в порядке:
icon/<type>/<subtype>icon/<type>/defaulticon/default
Таким образом, если вы хотите настроить макет иконки, вы можете переопределить соответствующее представление.
Пример отображения аватара пользователя:
// get the user
$user = elgg_get_logged_in_user_entity();
// show the small icon
echo elgg_view_entity_icon($user, 'small');
// don't add the user_hover menu to the icon
echo elgg_view_entity_icon($user, 'small', [
'use_hover' => false,
]);