Логирование действий пользователя в Joomla. Создание плагина Actionlog

от автора

На вашем сайте, внутреннем портале, в интернет-магазине кто-то что-то сделал, а потом всё сломалось: сайт открывается криво (или не открывается вообще?), перестали работать фоновые задачи в планировщике, установились неправильные скидки всем пользователям на все товары… Предположим, что с безопасностью у вас всё хорошо: Joomla свежая, актуальная, расширения — тоже. Да и в логах сервера и логах Joomla тоже чисто… Тогда остаётся ещё один источник информации — Лог действий пользователей Joomla. Основная его задача — помочь быстро найти кому настучать по рогам причину и устранить её.

Всё, что связано с действиями в админке — может логироваться: от обновления системы и компонентов, изменения настроек до редактирования и сохранения конкретных элементов (статьи, товары, категории и т.д.) и загрузки файлов через медиа менеджер. Лично мне нередко этот функционал помогал найти тех контент-менеджеров, кто дублирует названия товаров, создавая дубли и тем самым негативно влияя на SEO. Или же вдруг обнаруживается недозаполненная, но опубликованная карточка товара, которой не должно было быть, но она появилась. И ладно если б это был единичный случай.

Оговорка 1: статья рассчитана не только на тех, кто хорошо знает Joomla, но и на любопытствующих коллег из других технологических стеков. Поэтому некоторым очевидным терминам всё равно дано краткое пояснение.

Оговорка 2: на данный момент я рассматриваю Joomla скорее как PHP-фреймворк с натянутой на него готовой админкой, а не просто CMS. Расширение типа «компонент» в Joomla обычно представляет из себя набор различных CRUD-ов (в терминологии PHP-фреймворков), записи о действиях в которых можно хранить в логах. Поэтому статью следует больше рассматривать как начальную точку для проектирования и написания своего плагина (расширение, срабатывающие на триггеры событий Event Dispatcher) для своего же (скорее всего) компонента (CRUD-а).

Оглавление

Список литературы

Описание возможностей компонента Лога пользователей Joomla

Этот компонент был добавлен в ядро Joomla начиная с версии 3.9.0. Найти его можно в левом меню панели администратора: Пользователи — Лог действий пользователей.

Он предоставляет собой простой интерфейс для чтения и фильтрации записей.

Для всех записей указано расширение, к которому запись о событии относится.

Для всех записей указано расширение, к которому запись о событии относится.

На скриншоте я выделил колонку «расширение». По ней можно понять контекст записи о действии. На скриншоте видны разные компоненты:

  • «расширения» — действия, связанные с установкой, удалением и обновлением расширений, сохранением параметров.

  • «материалы» — штатный компонент для создания статей в Joomla. Его же нередко используют для создания каталогов чего угодно.

  • «SW JProjects» — сторонний компонент Joomla для ведения каталога расширений Joomla и сервера обновлений для них

  • «Лог действий» — собственно компонент лога действий пользователя Joomla

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

Правильный выход через кнопку «выйти» в наше время никто не делает, конечно. Это скорее исключение, так как все просто закрывают вкладку браузера. Но момент входа записывается точно, поэтому даже если какой-то компонент не умеет записывать логи об интересующих нас действиях пользователей, мы можем резко сузить круг «подозреваемых лиц» до тех, кто в данный момент времени находился в админке.

Мы можем отфильтровать записи по типу расширения и увидеть только то, что нас интересует. Для этого пользуемся кнопкой «параметры поиска» в списке записей событий. Список расширений зависит от установленных компонентов и того, поддерживают ли они стандартный для Joomla action log.

Фильтр действий пользователя Joomla по расширению

Фильтр действий пользователя Joomla по расширению

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

Ну и конечно доступна фильтрация записей по конкретному пользователю.

Параметры компонента Лог действий пользователя в Joomla

Настройки компонента Лог действий пользователей Joomla

Настройки компонента Лог действий пользователей Joomla

Настраиваемых параметров немного. Мы можем дополнительно логировать IP-адрес пользователя. По умолчанию эта функция отключена, видимо из-за европейских GDPR.

Самое полезное здесь — это настройка списка компонентов, в которых должны логироваться события.

Самое интересное здесь — возможность логирования запросов к REST API Joomla.

Если мы включим параметр «логировать запросы», то в выпадающем списке можно выбрать какие именно методы логировать: GET (получение данных по REST API). POST (создание сущности) и т.д. Подробнее о REST API в статье на Хабре «Web Services в Joomla 4».

Пользователь Joomla выполнил GET запрос по

Пользователь Joomla выполнил GET запрос по

Таким образом если ваша 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.

Логика работы плагина в целом состоит из следующих шагов:

  1. Проверить, в допустимом ли контексте вызвано событие. Обычно у компонента несколько сущностей (категории материалов и материалы; категории товаров, товары, производители товаров, характеристики товаров и т.д.), список их контекстов заносится в свойство класса плагина.

  2. Получить системное имя компонента вида com_mycomponent. В разных случаях мы получаем его или из контекста с помощью explode('.', $context), либо из $_GET массива с помощью объекта Input: $option = $app->getInput()->get('option').

  3. Проверить, а разрешено ли логировать действия в данном компоненте.

  4. В зависимости от типа события — сконструировать языковую константу и получить данные для подмены плейсхолдеров в ней.

  5. Собрать массив с сообщением и данными.

  6. Добавить массив в лог.

Языковые константы

Языковые константы ядра 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. В ней содержатся необходимые данные для конструирования языковых констант и источники данных для плейсхолдеров.

Скриншот таблицы #__action_log_config Joomla

Скриншот таблицы #__action_log_config Joomla
  • 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). В аргументах события мы имеем:

  • $contextstring — контекст события вида <component_name>.<entity>: com_content.article, com_contact.contact и т.д.

  • $article — объект Table сохранённой сущности. Вообще-то оно должно называться $item, так как это может быть не только статья, но и что угодно. Но видимо плагин изначально писали для материалов и оно так и осталось.

  • $isNewbool — логический флаг новая ли сущность или уже существующая.

  • $dataarray — данные отправленной в модель формы. Не все данные могут быть в объекте Table, некоторые поля формы могут храниться в других таблицах. Но в триггер передаётся лишь одна. Здесь зависит от того, какое поведение реализует модель компонента.

Штатный плагин подразумевает, что всё-таки большая часть данных формы хранится в одной основной таблице и аргумент $data не использует.

onContentAfterDelete — после удаления

Доступные аргументы — $context и $item. Необходимое нам системное имя компонента — получаем уже из объекта Input.

onContentChangeState — после смены состояния

Состояния: опубликовано / не опубликовано / в корзине / в архиве. Также ваш компонент может иметь собственную, более широкую систему состояний.

В аргументах события:

  • $contextstring — контекст события вида <component_name>.<entity>: com_content.article, com_contact.contact и т.д.

  • $pksarray — массив с id изменяемых сущностей.

  • $valueint — числовое значение состояние. 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.

Аргументированные замечания и предложения с радостью приму в комментариях.

Полезные ресурсы

Ресурсы сообщества:

Telegram:

Мой личный Telegram-канал — WebTolkRu.


ссылка на оригинал статьи https://habr.com/ru/articles/900338/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *