Логирование действий пользователя в Joomla. Создание плагина Actionlog
На вашем сайте, внутреннем портале, в интернет-магазине кто-то что-то сделал, а потом всё сломалось: сайт открывается криво (или не открывается вообще?), перестали работать фоновые задачи в планировщике, установились неправильные скидки всем пользователям на все товары... Предположим, что с безопасностью у вас всё хорошо: Joomla свежая, актуальная, расширения - тоже. Да и в логах сервера и логах Joomla тоже чисто... Тогда остаётся ещё один источник информации - Лог действий пользователей Joomla. Основная его задача - помочь быстро найти кому настучать по рогам причину и устранить её.
Всё, что связано с действиями в админке - может логироваться: от обновления системы и компонентов, изменения настроек до редактирования и сохранения конкретных элементов (статьи, товары, категории и т.д.) и загрузки файлов через медиа менеджер. Лично мне нередко этот функционал помогал найти тех контент-менеджеров, кто дублирует названия товаров, создавая дубли и тем самым негативно влияя на SEO. Или же вдруг обнаруживается недозаполненная, но опубликованная карточка товара, которой не должно было быть, но она появилась. И ладно если б это был единичный случай.
Оговорка 1: статья рассчитана не только на тех, кто хорошо знает Joomla, но и на любопытствующих коллег из других технологических стеков. Поэтому некоторым очевидным терминам всё равно дано краткое пояснение.
Оговорка 2: на данный момент я рассматриваю Joomla скорее как PHP-фреймворк с натянутой на него готовой админкой, а не просто CMS. Расширение типа "компонент" в Joomla обычно представляет из себя набор различных CRUD-ов (в терминологии PHP-фреймворков), записи о действиях в которых можно хранить в логах. Поэтому статью следует больше рассматривать как начальную точку для проектирования и написания своего плагина (расширение, срабатывающие на триггеры событий Event Dispatcher) для своего же (скорее всего) компонента (CRUD-а).
Оглавление
Список литературы
Список литературы
User Action Logs - документация для Joomla 3. Практически все положения из неё остались верны и для последующих версий.
Joomla User Manual - чуть обновлённый вариант документации для Joomla 5. Так же есть ИИ-перевод на русский язык.
На новом портале документации Joomla manual.joomla.org на момент написания статьи ещё нет примера плагина Action log, но ссылку оставлю, так как вся актуальная информация по ядру собирается именно там.
Триггеры ядра Joomla при CRUD-операциях - сопутствующая статья.
Создание плагинов с учётом новой структуры Joomla 4 - сопутствующая статья.
Joomla Extensions Development - объёмная книга греческого разработчика Никалоса Дионисопулоса. Посвящена Joomla разработке в целом, освещает вопросы архитектуры, причины применения некоторых подходов и т.д.
Описание возможностей компонента Лога пользователей Joomla
Этот компонент был добавлен в ядро Joomla начиная с версии 3.9.0. Найти его можно в левом меню панели администратора: Пользователи - Лог действий пользователей.
Он предоставляет собой простой интерфейс для чтения и фильтрации записей.
На скриншоте я выделил колонку "расширение". По ней можно понять контекст записи о действии. На скриншоте видны разные компоненты:
"расширения" - действия, связанные с установкой, удалением и обновлением расширений, сохранением параметров.
"материалы" - штатный компонент для создания статей в Joomla. Его же нередко используют для создания каталогов чего угодно.
"SW JProjects" - сторонний компонент Joomla для ведения каталога расширений Joomla и сервера обновлений для них
"Лог действий" - собственно компонент лога действий пользователя Joomla
Так, например, компонент "пользователи" (com_users
) логирует не только собственно действия с пользователями, но и моменты входа и выхода в админку.
Правильный выход через кнопку "выйти" в наше время никто не делает, конечно. Это скорее исключение, так как все просто закрывают вкладку браузера. Но момент входа записывается точно, поэтому даже если какой-то компонент не умеет записывать логи об интересующих нас действиях пользователей, мы можем резко сузить круг "подозреваемых лиц" до тех, кто в данный момент времени находился в админке.
Мы можем отфильтровать записи по типу расширения и увидеть только то, что нас интересует. Для этого пользуемся кнопкой "параметры поиска" в списке записей событий. Список расширений зависит от установленных компонентов и того, поддерживают ли они стандартный для Joomla action log.
Также есть возможность отфильтровать действия по конкретному пользователю и за выбранный период времени. К сожалению, периоды времени пока что не настраиваются и доступны только предустановленные значения.
Ну и конечно доступна фильтрация записей по конкретному пользователю.
Параметры компонента Лог действий пользователя в Joomla
Настраиваемых параметров немного. Мы можем дополнительно логировать IP-адрес пользователя. По умолчанию эта функция отключена, видимо из-за европейских GDPR.
Самое полезное здесь - это настройка списка компонентов, в которых должны логироваться события.
Самое интересное здесь - возможность логирования запросов к REST API Joomla.
Если мы включим параметр "логировать запросы", то в выпадающем списке можно выбрать какие именно методы логировать: GET
(получение данных по REST API). POST
(создание сущности) и т.д. Подробнее о REST API в статье на Хабре "Web Services в Joomla 4".
Таким образом если ваша Joomla связана с внешними системами по REST API, то историю взаимодействия с ними тоже можно отслеживать.
Версионность контента. Просмотр изменений.
Порой нам хотелось бы знать что именно было изменено и на что. Версионность контента возможна только в тех компонентах, что его поддерживают и где параметр сохранения версий включён. Так, в стандартных материалах Joomla должен быть включён параметр в настройках компонента - Форма - История версий.
Тогда на странице редактирования материала Joomla появится кнопка "версии".
Где можно не только их просмотреть и восстановить...
... но и сравнить, увидев конкретные внесённые изменения. Изменения показываются в отдельном всплывающем окне. Изменения подсвечиваются.
Если вы пишете свой собственный компонент, то можете реализовать это удобнее с точки зрения пользовательского опыта и в своём сообщении добавить сразу ссылку на diff-ы.
Архитектура базы данных
В базе данных Joomla 4 таблицы, связанных с логированием действий пользователей:
#__actionlogs
- основная таблица для хранения логов#__actionlogs_extensions
- таблица для хранения списка логируемых расширений. Данные этой таблицы образуют список компонентов для параметра Логировать действия в расширениях в настройках компонента. Столбецextension
в ней содержит значение системного имени компонента видаcom_content
,com_menus
,com_modules
и т.д.#__actionlogs_users
- параметры логирования действий для конкретных пользователей. Эти параметры можно настроить в профиле пользователя, вкладка "Лог действий"#__action_log_config
- параметры для конструирования языковой константы сообщения лога и данных для неё.
Анализ плагина action logs ядра Joomla
В Joomla штатные действия ядра записывает плагин Лог действий - Joomla. Он не имеет настраиваемых параметров. Файл класса плагина находится в plugins/actionlog/joomla/src/Extension/Joomla.php.
Логика работы плагина в целом состоит из следующих шагов:
Проверить, в допустимом ли контексте вызвано событие. Обычно у компонента несколько сущностей (категории материалов и материалы; категории товаров, товары, производители товаров, характеристики товаров и т.д.), список их контекстов заносится в свойство класса плагина.
Получить системное имя компонента вида
com_mycomponent
. В разных случаях мы получаем его или из контекста с помощьюexplode('.', $context)
, либо из$_GET
массива с помощью объектаInput
:$option = $app->getInput()->get('option')
.Проверить, а разрешено ли логировать действия в данном компоненте.
В зависимости от типа события - сконструировать языковую константу и получить данные для подмены плейсхолдеров в ней.
Собрать массив с сообщением и данными.
Добавить массив в лог.
Языковые константы
Языковые константы ядра Joomla для лога действий пользователя распределены между файлами локализаций двух плагинов - групп system
и actionlog
:
administrator/language/ru-RU/plg_actionlog_joomla.ini
administrator/language/ru-RU/plg_system_actionlogs.ini
Если мы откроем файлы локализации плагина группы actionlog
Joomla, то увидим в нём следующие строки:
PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал {type} <a href=\"{itemlink}\">{title}</a>"
PLG_SYSTEM_ACTIONLOGS_CONTENT_ARCHIVED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в архив {type} <a href=\"{itemlink}\">{title}</a>"
PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED="Пользователь <a href=\"{accountlink}\">{username}</a> удалил {type} {title}"
PLG_SYSTEM_ACTIONLOGS_CONTENT_PUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> опубликовал {type} <a href=\"{itemlink}\">{title}</a>"
PLG_SYSTEM_ACTIONLOGS_CONTENT_TRASHED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в корзину {type} <a href=\"{itemlink}\">{title}</a>"
PLG_SYSTEM_ACTIONLOGS_CONTENT_UNPUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> снял с публикации {type} <a href=\"{itemlink}\">{title}</a>"
PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED="Пользователь <a href=\"{accountlink}\">{username}</a> обновил {type} <a href=\"{itemlink}\">{title}</a>"
Имя языковой константы конструируется по формуле [text_prefix] + [entity] + [action]
.
$text_prefix
- это обычно свойство контроллера или модели компонента. В нём хранится системное имя компонента: com_categories
, com_content
, com_menus. Или [имя компонента + сущность]: com_banners_client
, com_banners_banners
.
Набор типов действий по умолчанию в Joomla интуитивно понятны. Суффикс ADD
для вновь созданных элементов, DELETED
- для удалённых и т.д.
Фрагмент entity в имени языковой константы в Joomla по умолчанию равен "CONTENT". Он используется в случаях, когда отсутствуют созданные языковые константы, но вывести что-то нужно.
Типы изменяемых сущностей
Ещё ряд языковых констант даёт нам название типов изменяемых сущностей, отвечая на вопрос "что?" - что было изменено / создано / удалено и т.д. В файле administrator/language/ru-RU/plg_actionlog_joomla.ini это строки
;...
PLG_ACTIONLOG_JOOMLA_TYPE_ARTICLE="материал"
PLG_ACTIONLOG_JOOMLA_TYPE_BANNER="баннер"
PLG_ACTIONLOG_JOOMLA_TYPE_BANNER_CLIENT="клиента"
PLG_ACTIONLOG_JOOMLA_TYPE_CATEGORY="категорию"
PLG_ACTIONLOG_JOOMLA_TYPE_COMPONENT="компонент"
PLG_ACTIONLOG_JOOMLA_TYPE_COMPONENT_CONFIG="Настройки компонента"
PLG_ACTIONLOG_JOOMLA_TYPE_CONTACT="контакт"
PLG_ACTIONLOG_JOOMLA_TYPE_FIELD="поле"
;...
Они формируются по формуле [text_prefix] + _TYPE_ + [entity]
.
Плейсхолдеры в языковых константах (переменные для строковой замены)
Вы уже обратили внимание на переменные в составе языковых констант. В примере выше мы можем увидеть
{accountlink}
- ссылку на пользователя в админке Joomla{username}
- имя пользователя{type}
- тип сущности: материал, баннер, модуль, параметры конфигурации, товар и т.д.{itemlink}
- ссылка в админке на сущность, с которой произошло событие{title}
- название / заголовок сущности
Также штатно обрабатываются ещё следующие плейсхолдеры, работающие везде:
{userid}
- id юзера, совершающего действие. Используется для формирования ссылок на него.{app}
- тип приложения: панель управления, API (Joomla REST API), CLI, сайт.
Некоторые плейсхолдеры используются только в определенных частях системы, например в REST API Joomla:
{verb}
- для логирования запросов REST API - тип запроса GET, POST, PUT и т.д.{url}
- для логирования запросов REST API - url запроса
Конструирование языковых констант
Посмотрим на структуру таблицы #__action_log_config
. В ней содержатся необходимые данные для конструирования языковых констант и источники данных для плейсхолдеров.
text_prefix
- см. о нём выше. Префикс для языковых констант.type_alias
- содержит в себе контекст выполнения действия.$context
содержит в себе системное имя компонента и сущности вида<com_component>.<entity>
. Если в этом списке нет нужного контекста - штатный плагин Joomla не сработает.table_name
- имя таблицы базы данных, из которых нужно выбирать данные в некоторых случаях. Например при смене состояния: опубликовано / не опубликовано * перемещено в корзину / перемещено в архив. При пакетных действиях на триггерonContentChangeState
приходит списокid
и чтобы получить заголовок статьи нужно сходить за ним в базу.type_title
- поле, в котором находится фрагмент языковой константы типа изменяемой сущности для данного контекста. Например, для контекстаcom_content.article
при формировании языковой константы для плейсхолдера{type}
будет создано PLG_ACTIONLOG_JOOMLA_TYPE_ARTICLE.id_holder
иtitle_holder
- содержат в себе названия свойств объектаTable
изменяемой сущности. Например, если мы отслеживаем материал Joomla, то для ссылки на созданный / изменённый материал нам нужен егоid
и он хранится в таблице#__content
в столбце с названиемid
. Аналогично заголовок материала хранится в таблице#__content
в столбце с названиемtitle
. Однако, у баннеров столбец для заголовка баннера называетсяname
и т.д.
Посмотрим на примере одного события onContentAfterSave
как работает штатный плагин.
<?php
// \Joomla\Plugin\Actionlog\Joomla\Extension\Joomla::onContentAfterSave
// Файл plugins/actionlog/joomla/src/Extension/Joomla.php
use Joomla\CMS\Event\Model;
/**
* After save content logging method
* This method adds a record to #__action_logs contains (message, date, context, user)
* Method is called right after the content is saved
*
* @param Model\AfterSaveEvent $event The event instance.
*
* @return void
*
* @since 3.9.0
*/
public function onContentAfterSave(Model\AfterSaveEvent $event): void
{
// Контекст вида com_content.article
$context = $event->getContext();
// Исторически это $article, хотя правильнее назвать $item
$article = $event->getItem();
// Логический флаг: создаётся новый элемент или редактируется уже существующий
$isNew = $event->getIsNew();
if (isset($this->contextAliases[$context])) {
$context = $this->contextAliases[$context];
}
// Параметры компонента. Тут находится список
// разрешённых к логированию компонентов.
// Этот список переопределяется настройками
// конкретного юзера в его профиле.
$params = $this->getActionLogParams($context);
// Not found a valid content type, don't process further
if ($params === null) {
return;
}
// $option - это системное имя компонента вида com_component.
[$option, $contentType] = explode('.', $params->type_alias);
// Можно ли логировать действия в данном компонент для данного юзера?
if (!$this->checkLoggable($option)) {
return;
}
// Конструируем языковую константу
// Добавляем нужные суффиксы к языковой константе.
if ($isNew) {
$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_ADDED';
$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
} else {
$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_UPDATED';
$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
}
// If the content type doesn't have its own language key, use default language key
if (!$this->getApplication()->getLanguage()->hasKey($messageLanguageKey)) {
$messageLanguageKey = $defaultLanguageKey;
}
$id = empty($params->id_holder) ? 0 : $article->{$params->id_holder};
// Массив с сообщением
$message = [
'action' => $isNew ? 'add' : 'update',
'type' => $params->text_prefix . '_TYPE_' . $params->type_title,
'id' => $id,
'title' => $article->{$params->title_holder} ?? '',
'itemlink' => ActionlogsHelper::getContentTypeLink($option, $contentType, $id, $params->id_holder, $article),
];
$this->addLog([$message], $messageLanguageKey, $context);
}
В массиве $message
хранятся данные для плейсхолдеров в языковой константе. Дополнительно, 4-м аргументов в $this->addLog()
можно передать id
пользователя, для которого создаётся запись. Обычно это id
текущего пользователя.
Решение без создания плагина
Можно обойтись и без создания собственного плагина. Если для вас сообщения вида "Пользователь [Сиреневый Енот] [обновил] [сущность] [ссылка на сущность]" достаточно информативны, то можно обойтись просто добавлением своих параметров в базу данных.
Вы добавляете свой компонент в список возможных логируемых компонентов (для выпадающего списка в настройках компонента Лог пользователей) в таблицу #__actionlogs_extensions
и затем добавляете параметры для конструирования языковых констант в таблицу #__action_log_config
. А дальше вам нужно лишь создать 4 файла локализации с текстами сообщений: 2 на английском и 2 на русском языках. Всю дальнейшую работу будет выполнять плагин ядра Joomla.
Сделать это можно при создании очередного релиза вашего компонента в sql-файлах пакета буквально парой запросов.
Задача решена. Дальше статью можно не читать.
Создание своего плагина
Если вам нужны более информативные сообщения в логах, где используется больше плейсхолдеров в языковых константах или же не все данные приходят в объекте Table
изменяемой сущности, то тогда потребуется создать полноценный плагин. Создаём плагин группы actionlog
по типовой для Joomla 4+ структуре файлов и классов. Здесь читаем статью Создание плагинов с учётом новой структуры Joomla 4.
Триггеры событий для плагинов (Event Dispatching)
Ранее писал статью "Триггеры ядра Joomla при CRUD-операциях", в которой рассказывается о различных событиях, вызываемых в моделях ядра Joomla. Модели компонентов ядра и немалая часть сторонних компонентов (но далеко не все) наследуют \Joomla\CMS\MVC\Model\AdminModel
(libraries/src/MVC/Model/AdminModel.php). Поэтому в них доступны все стандартные события:
onContentBeforeDelete
- перед удалением сущностиonContentAfterDelete
- после удаленияonContentBeforeSave
- перед сохранением данных сущностиonContentAfterSave
- после сохраненияonContentBeforeChangeState
- перед изменением состояния (опубликовано, не опубликовано, в корзине...)onContentChangeState
- после изменения состоянияonBeforeBatch
- перед пакетной обработкой нескольких сущностей
В некоторых случаях названия события отличаются, подробнее об этом смотрим в указанной статье.
При триггере события в плагин передаются данные, для каждого события - свои. Приведу примеры:
onContentAfterSave - после сохранения
Событие вызывается после сохранения любой сущности в Joomla (повторюсь, если модели компонента наследуют AdminModel
). В аргументах события мы имеем:
$context
-string
- контекст события вида<component_name>.<entity>
:com_content.article
,com_contact.contact
и т.д.$article
- объектTable
сохранённой сущности. Вообще-то оно должно называться$item
, так как это может быть не только статья, но и что угодно. Но видимо плагин изначально писали для материалов и оно так и осталось.$isNew
-bool
- логический флаг новая ли сущность или уже существующая.$data
-array
- данные отправленной в модель формы. Не все данные могут быть в объектеTable
, некоторые поля формы могут храниться в других таблицах. Но в триггер передаётся лишь одна. Здесь зависит от того, какое поведение реализует модель компонента.
Штатный плагин подразумевает, что всё-таки большая часть данных формы хранится в одной основной таблице и аргумент $data
не использует.
onContentAfterDelete - после удаления
Доступные аргументы - $context
и $item
. Необходимое нам системное имя компонента - получаем уже из объекта Input.
onContentChangeState - после смены состояния
Состояния: опубликовано / не опубликовано / в корзине / в архиве. Также ваш компонент может иметь собственную, более широкую систему состояний.
В аргументах события:
$context
-string
- контекст события вида<component_name>.<entity>
:com_content.article
,com_contact.contact
и т.д.$pks
-array
- массив с id изменяемых сущностей.$value
-int
- числовое значение состояние.0
- не опубликовано,1
- опубликовано,2
- в архиве,-2
- в корзине.
Далее, на каждое событие вы конструируете языковые константы тем же образом. что и штатный плагин. А в массив $message
помещаете данные для всех необходимых плейсхолдеров. Приведу пример из плагина логирования действий пользователей в админке компонента SW JProjects (GitHub).
<?php
/**
* After save content logging method.
* This method adds a record to `#__action_logs` contains (message, date, context, user)
* Method is called right after the content is saved
*
* @param string $context
* @param object $item
* @param bool $isNew
* @param array $data
*
* @return void
*
* @since 2.4.0 // $context, $item, $isNew, $data
* @todo use Model\AfterSaveEvent $event when Joomla 6 will be released
*/
public function onContentAfterSave($context, $item, $isNew, $data): void
{
// На момент выпуска релиза ещё немало сайтов было на Joomla 4,
// поэтому из-за сохранения обратной совместимости с ней
// используется ещё старый подход.
// На новые рельсы перейдём после релиза Joomla 6 осенью 2025г.
// $context = $event->getContext();
// $item = $event->getItem();
// $isNew = $event->getIsNew();
// $data = $event->getData();
// Массив с допустимыми контекстами для данного компонента
if (!in_array($context, $this->contextList))
{
return;
}
list($option, $contentType) = explode('.', $context);
// Можно ли логировать данный компонент для конкретного юзера?
if (!$this->checkLoggable($option))
{
return;
}
// Новая сущность или редактируемая старая?
if ($isNew) {
$messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_' . strtoupper($contentType) . '_ADDED';
$data['id'] = $item->id;
} else if ($context == 'com_swjprojects.key' && $data['key_regenerate'] == 1) {
$messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_KEY_REGENERATED';
} else {
$messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_' . strtoupper($contentType) . '_UPDATED';
}
// Для получения title отдельный метод, так как в компоненте не стандартная мультиязычность
$message = [
'action' => $isNew ? 'add' : 'update',
'type' => 'PLG_ACTIONLOG_SWJPROJECTS_TYPE_' . strtoupper($contentType),
'id' => $item->id,
'title' => $this->getItemTitle($context, $data),
'itemlink' => 'index.php?option=com_swjprojects&task=' . $contentType . '.edit&id=' . $item->id,
];
// В случае необходимости можно использовать любое количество
// плейсхолдеров для замены.
// Добавляем здесь нужные для нужных контекстов.
if (!in_array($contentType, ['project', 'category', 'key']))
{
$message['projectTitle'] = $this->getProjectTitle($item->project_id);
$message['projectLink'] = 'index.php?option=com_swjprojects&task=project.edit&id=' . $item->project_id;
}
$this->addLog([$message], $messageLanguageKey, $context);
}
В этом примере видно, что для некоторых контекстов (категория, проект и лицензионный ключ) нам не хватает стандартных значений и мы добавляем свои. Языковые константы выглядят следующим образом:
; Добавление документации для цифрового проекта
PLG_ACTIONLOG_SWJPROJECTS_DOCUMENT_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал документацию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects"
; Добавление лицензионного ключа
PLG_ACTIONLOG_SWJPROJECTS_KEY_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал лицензионный ключ id <code>{title}</code> в компоненте SW JProjects"
; Работа с версиями программного обеспечения
PLG_ACTIONLOG_SWJPROJECTS_VERSION_PUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> опубликовал версию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects"
PLG_ACTIONLOG_SWJPROJECTS_VERSION_TRASHED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в корзину версию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects"
Так это выглядит в панели администратора.
Дополнительные детали
Метод checkLoggable()
Конструктор класса плагина обычно выглядит следующим образом:
<?php
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
*
* @since 2.4.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config)
{
parent::__construct($dispatcher, $config);
$params = ComponentHelper::getComponent('com_actionlogs')->getParams();
// Массив с системными именами логируемых компонентов
$this->loggableExtensions = $params->get('loggable_extensions', []);
// То же самое для REST API
$this->loggableApi = $params->get('loggable_api', 0);
// Логируемые методы REST API
$this->loggableVerbs = $params->get('loggable_verbs', []);
}
А сам метод проверки выглядит так:
<?php
/**
* Function to check if a component is loggable or not
*
* @param string $extension The extension that triggered the event
*
* @return boolean
*
* @since 2.4.0
*/
protected function checkLoggable(string $extension): bool
{
return in_array($extension, $this->loggableExtensions);
}
Заключение
Иногда сохранённые логи действий пользователей помогают быстрее найти решение проблемы, если она вызвана человеческим фактором. Да, может быть не всё удобно с точки зрения удобства использования и поиска, но это Open Source и это в составе ядра Joomla.
Надеюсь, мне удалось понятно изложить эту тему и по этой статье можно будет быстро внедрить нужный функционал в ваши компоненты Joomla.
Аргументированные замечания и предложения с радостью приму в комментариях.
Полезные ресурсы
Ресурсы сообщества:
https://vc.ru/s/1146097-joomla - Сообщество Joomla на VC.
Telegram:
Мой личный Telegram-канал - WebTolkRu.