Forum categories

Механизм хуков в Cotonti. Как это работает? Примеры.

В нужном месте, где нужно "вклинить" или "повесить" свой код, - нужно прописать "крючок", то есть хук, на который будем вешать свой пользовательский код, а сделать это можно вызовом функции в нужном участке кода


webitproff
webitproff • 2026-05-14 14:23 #1

 

В Cotonti механизм хуков работает так:

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


// Удаление товара предварительно - хук на который вешаем удаление переводов товара
foreach (cot_getextplugins('market.delete.first') as $pl) {
    include $pl;
}

         
То есть при запуске файла MarketControlService.php

до хука

// Хук для дополнительных действий после удаления
foreach (cot_getextplugins('market.delete.done') as $pl) {
    include $pl;
}

система сама ищет файлы в папках плагинов, где в заголовке указано Hooks=market.delete.first.

Файл plugins/i18n4marketpro/i18n4marketpro.market.delete.first.php как раз содержит такой заголовок и удаляет переводы. 
Затем продолжается выполнение кода и удаление товара.

В Cotonti хук — это способ для плагинов выполнить свой код в строго определённых местах ядра или модулей.
Разработчик модуля market разместил в методе MarketControlService::delete() вызов:
 

foreach (cot_getextplugins('market.delete.first') as $pl) {
   include $pl;
}

 

Этот код ищет все файлы плагинов, у которых в самом начале есть секция:
 

/* ====================
[BEGIN_COT_EXT]
Hooks=market.delete.first
[END_COT_EXT]
==================== */

 

Когда плагин i18n4marketpro активен, Cotonti находит его файл
plugins/i18n4marketpro/i18n4marketpro.market.delete.first.php, и при заходе в delete() включает его содержимое через include.
Внутри этого файла выполняется удаление записей из таблицы cot_i18n4marketpro_pages:
 

if (Cot::$db->tableExists('cot_i18n4marketpro_pages')) {
   Cot::$db->delete(Cot::$db->i18n4marketpro_pages, 'ipage_id = ?', $id);
}

 

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

Если плагин отключён, Cotonti игнорирует его хуки.
cot_getextplugins('market.delete.first') не находит ни одного файла, цикл ничего не включает, переводы остаются в базе, и при попытке удалить товар база данных выдаёт ошибку «Cannot delete or update a parent row: a foreign key constraint fails».
Именно эта ошибка перехватывается catch (Throwable $e) и приводит к return false в delete().
А так как код market.edit.php после неудачного удаления продолжает выполняться, он запускает cot_market_validate() с пустыми данными, и пользователь видит ошибки «Код категории бла-бла пиндец» и т.д.

Кратко: хуки позволяют плагинам «вклиниваться» в процесс удаления товара или другой нужный разработчику.
Сейчас вызов хука в MarketControlService::delete() уже написан - теперь можно писать файлы в плагинах с заголовком Hooks=market.delete.first и быть уверенным в том, что логика куда в этих файлах будет выполняться при обращении к нашему крючку в MarketControlService.php.
 

написано в образовательных целях для контекста и картины в целом!

 

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

<?php
/**
* [BEGIN_COT_EXT]
* Hooks=market.delete.done
* [END_COT_EXT]
*/
/**
* featuredtopicsmarket.market.delete.done.php - Delete links on product delete
*
* featuredtopicsmarket plugin for Cotonti 0.9.26, PHP 8.4+
* Filename: featuredtopicsmarket.market.delete.done.php
*
* Date: May 14Th, 2026
* @package featuredtopicsmarket
* @version 2.7.8
* @author webitproff
* @copyright Copyright (c) webitproff 2026 | https://github.com/webitproff
* @license BSD
*/
defined('COT_CODE') or die('Wrong URL');
require_once cot_incfile('featuredtopicsmarket', 'plug'); 
global $db, $db_featured_topics_market, $id;
if ($id > 0)
{
   $db->delete($db_featured_topics_market, "rtm_from_id = ? OR rtm_to_id = ?", [$id, $id]);
}
/* просто как шпаргалка
    global $db, $db_x, $id;
    if ($id > 0) {
        $table = $db_x . 'featured_topics_market';
        $db->delete($table, "rtm_from_id = ? OR rtm_to_id = ?", [$id, $id]);
    } 
*/

 

 

This post was edited by webitproff (2026-05-14 16:04, 2 months ago)
🗿

🧙‍♂️ Well met, good traveler! Fate has guided your steps to our humble realm. Here, wise sages and masters of the coding craft ⚒️📜 gather to unravel the mysteries of the code ✨⚙️, share their knowledge, and add new chapters to our chronicles.
⬅️ To the left lie ancient scrolls 📚 filled with forgotten wisdom. ⬆️ Straight ahead, friendly folk offer counsel 💬 to those in need. ➡️ To the right, you may become a chronicler ✍️ yourself, sharing your craft and leaving words of wisdom for those yet to come.
📝 Delay no longer—tell us the name by which you are known, complete the rite of registration 🛡️, and join our fellowship!
🏰 Our brotherhood holds no secret initiation, yet many halls remain closed to wandering guests, for some knowledge 💎 is reserved for those who choose to walk this path beside us.