Именование хуков, объявление и чтение. Принципы и правила. Обзорное руководство

Для разработчиков это руководство является справочником, обеспечивающим корректную интеграцию кода в архитектуру ядра Cotonti. Понимание принципов работы хуков.

0 Опубликована Опубликовано в: Cotonti Siena CMF > Cotonti - чтиво. Документация.
Именование хуков, объявление и чтение. Принципы и правила. Обзорное руководство

Введение

Данное руководство является результатом анализа исходного кода Cotonti Siena, в частности, функций cot_extension_install() (файл system/extensions.php) и cot_getextplugins() (файл system/functions.php). Цель — предоставить исчерпывающее описание механизма работы хуков: от правил их именования до регистрации и вызова. Изложение построено исключительно на фактах, извлечённых из предоставленного кода и официальной документации Cotonti, без предположений и домыслов.

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

Терминология и контекст

Прежде чем перейти к деталям, необходимо определить ключевые понятия.

Хук (hook) — это специальная точка в программном коде Cotonti, в которой может быть выполнен сторонний скрипт (обработчик) для изменения логики выполнения основной программы. Фактически, хук — это именованное событие, на которое могут «подписаться» расширения.

Обработчик хука — это PHP-файл, входящий в состав плагина или модуля, который содержит код, исполняемый в момент срабатывания хука. В Cotonti обработчик подключается через конструкцию include.

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

Чтение хука — динамическая операция, выполняемая ядром в момент выполнения скрипта. Она заключается в поиске в базе данных всех обработчиков, зарегистрированных на данный хук, и их последовательном подключении.

Часть I. Именование хуков: правила и соглашения

Имя хука — это строка, однозначно идентифицирующая точку расширения в коде. Правильное именование критически важно, поскольку оно является ключом, по которому ядро находит обработчики в базе данных.

1.1. Общая структура имени хука

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

Таким образом, общий формат имени хука можно представить как:

<расширение>.<часть>.<режим>.<действие>

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

1.2. Соглашения об именовании частей

При создании собственных хуков (например, при разработке модуля или плагина) следует придерживаться следующих правил:

  • Уникальность: имя хука должно быть уникальным в рамках всей системы, чтобы избежать конфликтов с ядром и другими расширениями.
  • Стиль: рекомендуется использовать нижний регистр (lowercase) и разделять слова точками. Это соответствует стилю, принятому в ядре Cotonti.
  • Осмысленность: имя должно отражать назначение хука. Например, market.delete.first явно указывает на действие удаления в модуле market и на то, что хук вызывается перед (first) выполнением операции.
  • Префикс расширения: первым элементом имени настоятельно рекомендуется использовать код вашего расширения (например, myplugin), чтобы гарантировать отсутствие коллизий.

В документации также приводятся требования к имени самого расширения: оно должно быть уникальным, состоять только из строчных букв, цифр и дефисов.

1.3. Специальные хуки

Существуют специальные имена хуков, имеющие особое значение:

  • standalone: используется для страниц, которые доступны напрямую через plug.php?e=ваш_плагин. Такой хук не привязан к конкретному месту в ядре, а вызывается при прямом обращении к плагину.
  • ajax: используется для обработки AJAX-запросов. Файл с таким хуком подключается при вызове plug.php?r=ваш_плагин и, как правило, не выводит шапку и подвал сайта.

1.4. Практические примеры из ядра

В ядре Cotonti можно найти множество примеров именования хуков:

  • index.main — основная часть главной страницы.
  • forums.posts.rights — проверка прав при просмотре постов форума.
  • search.page.query — формирование запроса при поиске по страницам.
  • profile.update.<code> — обновление профиля пользователя, где <code> — динамическая часть.

Эти примеры демонстрируют следование описанной выше структуре.

Часть II. Объявление хуков в файлах расширений

Объявление хука — это процесс связывания файла-обработчика с именем хука. В Cotonti это делается не в setup-файле, а непосредственно в заголовке каждого файла-обработчика.

2.1. Структура блока [BEGIN_COT_EXT]

В начале каждого PHP-файла, который является обработчиком хука, должен располагаться специальный блок в комментарии. Он начинается с [BEGIN_COT_EXT] и заканчивается [END_COT_EXT]. Внутри блока перечисляются параметры, разделённые переводами строк, в формате Ключ=Значение.

Пример:

<?php
/* ====================
[BEGIN_COT_EXT]
Hooks=myplugin.main
Order=10
[END_COT_EXT]
==================== */

/**
 * @package MyPlugin
 * @copyright (c) 2026 Your Name
 * @license BSD
 */

defined('COT_CODE') or die('Wrong URL.');

// Код обработчика
?>

2.2. Параметр Hooks

Параметр Hooks является обязательным для файла-обработчика, если только это не standalone-часть (для неё Hooks может отсутствовать или быть равным standalone). Значением может быть одно имя хука или несколько, разделённых запятыми. Например:

Hooks=market.delete.first

или

Hooks=header.tags,header.first

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

2.3. Параметр Order

Параметр Order определяет порядок, в котором обработчики будут выполняться, если на один хук подписано несколько плагинов. Значение — целое число. Значение по умолчанию — 10.

Чем меньше число, тем раньше будет выполнен обработчик. Если у нескольких обработчиков указано одинаковое значение Order, они выполняются в порядке их установки в базе данных.

2.4. Параметры Part и File

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

  • Part: вторая часть имени файла (например, index для файла pluginname.index.php). Значение по умолчанию — main.
  • File: имя файла без расширения (например, pluginname.index).

Однако, при установке расширения ядро (cot_extension_install()) сканирует все файлы в папке плагина и автоматически определяет эти параметры на основе имени файла. Поэтому в большинстве случаев указывать Part и File вручную не требуется.

2.5. Роль setup-файла

Файл code.setup.php содержит метаданные о расширении (название, версия, зависимости, права доступа и т.д.), но не используется для регистрации хуков. В коде функции cot_extension_install() явно указано, что файлы с частями setup, install, uninstall, configure игнорируются при сканировании на предмет хуков:

$cot_ext_ignore_parts = ['configure', 'install', 'setup', 'uninstall'];

и

if (preg_match("#^$extensionCode(\.([\w\.]+))?.php$#", $f, $mt)
    && (!isset($mt[2]) || !in_array($mt[2], $cot_ext_ignore_parts)))

Таким образом, блок [BEGIN_COT_EXT] в setup-файле для целей регистрации хуков не читается. Хуки должны быть объявлены в отдельных файлах-обработчиках.

2.6. Пример полного файла-обработчика

Ниже приведён полный пример файла-обработчика для плагина myplugin, который подписывается на хук market.delete.first:

<?php
/* ====================
[BEGIN_COT_EXT]
Hooks=market.delete.first
Order=5
[END_COT_EXT]
==================== */

/**
 * Удаление связанных данных перед удалением товара в модуле Market.
 *
 * @package myplugin
 * @version 1.0.0
 * @author Your Name
 * @copyright (c) 2026 Your Name
 * @license BSD
 */

defined('COT_CODE') or die('Wrong URL.');

// Пример: удаление записей из связанной таблицы
if (Cot::$db->tableExists('cot_myplugin_market_data')) {
    Cot::$db->delete('cot_myplugin_market_data', 'item_id = ?', [$id]);
}

Часть III. Чтение и регистрация хуков в ядре

Механизм регистрации и чтения хуков реализован в двух ключевых функциях: cot_extension_install() и cot_getextplugins().

3.1. Функция cot_extension_install(): сканирование и регистрация

Эта функция вызывается при установке или обновлении расширения. Она выполняет следующие шаги, связанные с хуками:

  1. Сканирование папки расширения: Функция открывает директорию плагина или модуля и перебирает все файлы.
  2. Фильтрация файлов: С помощью регулярного выражения отбираются файлы, имя которых соответствует шаблону code.php или code.part.php. Файлы, у которых part входит в список игнорируемых (setup, install, uninstall, configure), пропускаются.
  3. Чтение блока [BEGIN_COT_EXT]: Для каждого отобранного файла вызывается функция cot_infoget(), которая извлекает содержимое блока [BEGIN_COT_EXT] (или [SED_EXTPLUGIN] для устаревшего формата).
  4. Извлечение хуков: Из полученного массива $part_info извлекается значение Hooks. Если оно не указано, предполагается, что это standalone (для плагинов) или module (для модулей).
  5. Извлечение порядка: Извлекается значение Order. Если не указано, используется значение по умолчанию COT_PLUGIN_DEFAULT_ORDER (равное 10).
  6. Формирование записей для БД: Для каждого хука из списка создаётся массив с информацией: pl_hook (имя хука), pl_code (код расширения), pl_file (имя файла), pl_part (часть), pl_order (порядок), pl_active (флаг активности).
  7. Запись в базу данных: Сформированные записи передаются в функцию cot_plugin_add(), которая выполняет вставку в таблицу cot_plugins (или $db_plugins).

Важно отметить, что при обновлении расширения старые записи о хуках удаляются (cot_plugin_remove()), и регистрация выполняется заново.

3.2. Функция cot_getextplugins(): выборка и подключение

Эта функция вызывается в ядре в местах, где предусмотрены хуки (например, foreach (cot_getextplugins('admin.cache.disk.first') as $pl) { include $pl; }). Она выполняет следующие действия:

  1. Инициализация: Объявляются глобальные переменные, в том числе массив $cot_plugins, который содержит все зарегистрированные хуки, загруженные из базы данных при старте системы.
  2. Проверка наличия хука: Если для указанного имени хука в массиве $cot_plugins нет записей, функция возвращает пустой массив.
  3. Перебор обработчиков: Для каждого зарегистрированного обработчика:
    • Определяется директория (модули или плагины) и категория для проверки прав доступа (cot_auth).
    • Проверка прав: Вызывается cot_auth($cat, $opt, $permission). Если прав нет, обработчик пропускается. По умолчанию $permission равен 'R' (право на чтение).
    • Фильтрация по расширению: Если функции передан параметр $extensionCode, обработчики других расширений пропускаются.
    • Проверка существования файла: Если включена опция $cfg['checkHookFileExistence'] (по умолчанию включена), проверяется, доступен ли файл для чтения. Если файла нет:
      • Формируется сообщение об ошибке с использованием языковой строки hookFileNotFound.
      • Ошибка записывается в лог через cot_log().
      • Если текущий пользователь — администратор, ему выводится предупреждение.
      • Обработчик пропускается.
  4. Сбор путей: Если все проверки пройдены, полный путь к файлу добавляется в результирующий массив $extPlugins.
  5. Триггер кэша: После обхода всех обработчиков вызывается $cache->trigger($hook) (если объект кэша существует). Это уведомляет систему кэширования о срабатывании хука.
  6. Возврат результата: Функция возвращает массив путей к файлам, которые будут подключены в вызывающем коде через include.

Таким образом, cot_getextplugins() выполняет роль «читателя» хуков: она находит все активные обработчики, проверяет их права и доступность, и возвращает их для подключения.

3.3. Хранение в базе данных

Информация о зарегистрированных хуках хранится в таблице cot_plugins (или с префиксом, указанным в $db_plugins). Основные поля:

  • pl_id — уникальный идентификатор записи.
  • pl_hook — имя хука.
  • pl_code — код расширения (плагина или модуля).
  • pl_part — часть файла (например, main, first, tags).
  • pl_file — имя файла-обработчика.
  • pl_order — порядок выполнения.
  • pl_active — флаг активности (1 — активно, 0 — отключено).
  • pl_module — флаг, указывающий, является ли расширение модулем (1) или плагином (0).

При каждом запросе к сайту эта таблица полностью вычитывается в массив $cot_plugins, сгруппированный по имени хука. Это позволяет cot_getextplugins() работать без дополнительных запросов к БД.

3.4. Динамические хуки

В некоторых случаях имя хука формируется динамически. Например, в коде можно встретить cot_getextplugins('profile.update.' . $code), где $code — переменная, содержащая имя расширения. Это позволяет создавать хуки, специфичные для каждого расширения, без необходимости регистрировать их заранее. Однако такие хуки должны быть объявлены в файлах-обработчиках с использованием того же динамического подхода, что на практике применяется редко.

Часть IV. Порядок выполнения обработчиков

Порядок выполнения обработчиков на один хук определяется значением pl_order (параметр Order). Сортировка производится по возрастанию: сначала выполняются обработчики с меньшим значением Order.

Если у нескольких обработчиков одинаковый Order, они выполняются в порядке их pl_id, то есть в порядке добавления в базу данных (обычно это порядок установки).

Значение по умолчанию COT_PLUGIN_DEFAULT_ORDER равно 10. Это означает, что если разработчик не указал Order, его обработчик будет выполняться после всех, у кого Order меньше 10, и до тех, у кого больше.

Пример: если Плагин A имеет Order=5, Плагин B — Order=10 (по умолчанию), Плагин C — Order=15, то порядок выполнения будет: A → B → C.

Если несколько плагинов имеют Order=10, они выполнятся в порядке установки.

Часть V. Частые ошибки и их последствия

В процессе разработки и установки расширений встречаются типовые ошибки, связанные с хуками.

5.1. Ошибки в объявлении

Объявление хука в setup-файле. Как было показано в анализе cot_extension_install(), файлы с part=setup игнорируются при регистрации хуков. Если разработчик поместил блок [BEGIN_COT_EXT] с Hooks=... только в code.setup.php, хук не будет зарегистрирован, и обработчик никогда не вызовется. Последствие: плагин не работает, хотя может быть активен.

Некорректный синтаксис блока [BEGIN_COT_EXT]. Если блок не закрыт ([END_COT_EXT]), или в нём опечатка в имени параметра (Hook= вместо Hooks=), функция cot_infoget() не сможет корректно распарсить информацию, и хук не будет зарегистрирован. Последствие: аналогично — плагин не работает.

Несовпадение имени файла и ожидаемого шаблона. Если файл называется, например, myplugin.myhook.php, но в блоке [BEGIN_COT_EXT] указан Part=main, ядро может неправильно сформировать путь. Однако, поскольку cot_extension_install() автоматически определяет Part из имени файла, эта ошибка возможна только при ручном вмешательстве.

5.2. Ошибки в именовании

Использование имени хука, не существующего в ядре. Если разработчик указал Hooks=myplugin.nonexistent, ядро зарегистрирует этот хук, но никогда не вызовет cot_getextplugins() с таким именем. Обработчик останется «висеть» в базе, но не будет выполняться. Последствие: плагин не работает, ошибок не выводится.

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

Опечатка в имени хука. Hooks=market.delet.first (пропущена e) вместо Hooks=market.delete.first. Ядро зарегистрирует хук с опечаткой, но cot_getextplugins('market.delete.first') его не найдёт. Последствие: обработчик не вызывается.

5.3. Ошибки в чтении

Несоответствие прав доступа. Функция cot_getextplugins() проверяет права через cot_auth(). Если у группы пользователей нет права на чтение (R) для данного расширения, обработчик будет пропущен. Это может произойти, если в setup-файле неправильно указаны Auth_guests или Auth_members. Последствие: плагин не работает для определённых групп пользователей.

Отсутствие файла обработчика. Если файл, указанный в базе (например, plugins/myplugin/myplugin.myhook.php), был удалён вручную или переименован, cot_getextplugins() сгенерирует ошибку hookFileNotFound, запишет её в лог и пропустит обработчик. Если включён режим отладки, администратор увидит предупреждение. Последствие: плагин не работает, в логе появляются ошибки.

5.4. Ошибки прав доступа

Неверная категория в cot_auth(). Для плагинов категория — 'plug', опция — код плагина. Для модулей — код модуля, опция — 'a'. Если разработчик ошибся в определении типа расширения (указал pl_module=0 вместо 1), проверка прав будет выполняться по неверной категории, и обработчик может быть пропущен. Последствие: плагин или модуль не работает.

Часть VI. Практические рекомендации

На основе анализа кода и документации можно сформулировать следующие рекомендации.

  1. Всегда объявляйте хуки в файлах-обработчиках, а не в setup-файле. Это требование ядра.
  2. Используйте префикс расширения в имени хука. Например, myplugin.main. Это гарантирует уникальность.
  3. Указывайте Order осознанно. Если ваш обработчик должен выполниться до или после других, задайте соответствующее значение. По умолчанию — 10.
  4. Проверяйте синтаксис блока [BEGIN_COT_EXT]. Убедитесь, что он закрыт, и параметры написаны без ошибок.
  5. Не удаляйте и не переименовывайте файлы-обработчики после установки. Если это необходимо, переустановите расширение.
  6. При отладке используйте $cfg['debug_mode']. В этом режиме cot_getextplugins() записывает имена сработавших хуков в массив $cotHooksFired, что помогает понять, какие хуки вызываются.
  7. Следите за правами доступа. Убедитесь, что в setup-файле правильно указаны Auth_guests и Auth_members для вашего расширения.

Заключение

Механизм хуков в Cotonti представляет собой стройную систему, основанную на регистрации обработчиков в базе данных и их динамическом подключении. Понимание правил именования, объявления и чтения хуков является ключевым для разработки качественных расширений и администрирования сайта. Данное руководство, основанное на анализе исходного кода, предоставляет необходимую базу знаний для работы с этим механизмом.

Приложение А. Справочные константы

  • COT_PLUGIN_DEFAULT_ORDER = 10 — порядок по умолчанию для обработчиков хуков.
  • COT_GROUP_GUESTS, COT_GROUP_INACTIVE, COT_GROUP_BANNED, COT_GROUP_SUPERADMINS — группы пользователей, используемые при установке прав.

Приложение Б. Полный список шагов при установке расширения

  1. Вызов cot_extension_install($code, $isModule).
  2. Проверка наличия setup-файла.
  3. Чтение информации о расширении (cot_infoget).
  4. Проверка версии (для обновления).
  5. Удаление старых привязок хуков (cot_plugin_remove).
  6. Сканирование папки расширения.
  7. Для каждого файла (кроме setup, install, uninstall, configure):
    • Чтение блока [BEGIN_COT_EXT].
    • Извлечение Hooks и Order.
    • Формирование записей для БД.
  8. Запись новых привязок в БД (cot_plugin_add).
  9. Установка конфигурации.
  10. Установка прав доступа.
  11. Применение патчей (для обновления).
  12. Очистка кэша ($cache->clear()).
Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям
webitproff
webitproff

Оффлайн

Последняя авторизация: 12.10.2026 18:21

Обо мне кратко
Поддержка и разработка веб-проектов на CMF Cotonti: приватные мессенджеры через сайт, открытые и закрытые небольшие социальные сети, торговые площадки и маркетплейсы, портал биржи фриланса и услуг, каталоги товаров оптовых поставщиков, дропшиппинг-платформы, интернет-магазины и многое другое.
Смотреть разработки и скачать
Публичное портфолио моих работ и разработок
Телеграм для сообщений
@webitproff
Телеграм-канал
@s/aBuyFILE
Публичный профиль
  • Дата размещения 11.10.2026 15:50
  • Обновлено 11.10.2026 15:50

Похожие страницы

Изучаем принцип работы хуков в Cotonti CMF
1 Хуки (hooks) в Cotonti CMF — это механизм расширений, который позволяет подключать код в различные точки жизненного
Журнал событий. Принципы работы логирования в Cotonti
2 Журнал событий (Логи) в админ-панелиГде найти: Админ-панель → Other (Прочее) → Log (Журнал).Что это такоеЭто история
Человекопонятный URL и правила его использования
3 Формирование человекопонятных урлов – при всей их важности – часто недооценивается или не понимается разработчиками
AJAX-части плагинов в Cotonti Siena. Принципы и примеры
4 AJAX-части плагинов в Cotonti Siena техническое руководство (фактическое описание, основано по-большей части из старой
Cotonti Siena CMF • 10.03.2026 08:45 webitproff
Список хуков в файле "forums.posts.php" Cotonti CMF
5 В файле "forums.posts.php" Cotonti CMF используются различные хуки, которые обеспечивают гибкость в обработке