Хук (от англ. hook) это специальное место в программе, вкотором может быть выполнен какой-либо сторонний скрипт (в данном случае соответствующая часть плагина или модуля), с тем чтобы изменить логику исполнения основной программы. Можно рассматривать этот механизм, как некоторое событие, которое должно быть обработано специальным кодом. В реальности Cotonti подключает соответствующий PHP файл, зарегистрированный как обработчик соответствующего события (хука). Рассмотрим программу в которой есть Хук:
$foo = 'Повелитель добра'; $bar = 'уничтожил'; $baz = 'все зло на планете!'; // ... // Обработчик хука здесь // ... echo "$foo $bar $baz";
Теперь предположим у нас есть обработчик данного хука, который имеет доступ ко всем переменным в данной областивидимости (в контексте вызова). Этот обработчик может выглядеть например так:
$foo .= ' и его могущественные помощники'; $bar = 'уничтожили почти ';
Во время выполнения Cotonti, код будет преобразован в следующую последовательность:
$foo = 'Повелитель добра'; $bar = 'уничтожил'; $baz = 'все зло на планете!'; $foo .= ' и его могущественные помощники'; $bar = 'уничтожили почти '; echo "$foo $bar $baz";
Таким образом, хуки это ваши помощники в деле расширения возможностей текущего кода. В Cotonti их существует достаточно большое количество, что позволяет изменить практически все.
Первый вопрос на который стоит ответить прежде чем писать очередную часть своего расширения — это то, какой функционал системы мы хотим изменить. А следовательно какой хут стоит для этого использовать. Конкретный список доступных хуков зависит от многих факторов: того какой модуль вызван, какая его часть при этом сработает, и какие действия будут выполнены в процессе работы скрипта. В зависимости от условий будут обработаны соответствующие хуки и вызваны соответствующие им обработчики.
Некоторые хуки в системе вызываются практически всегда и строго в определенном порядке относительно друг друга:
Recource
или в случае, когда надо переопределить переменные касающиеся тем/языковых данных/ресурсов и других параметров;В зависимости от запрошенной страницы сайта и вызова того или иного обработчика (расширения) могут быть вызваны следующие хуки:
Раз уж зашла речь о системных хуках, то стоит упомянуть и третью группу — хуки расширяющие функционал системных функций. Эти хуки определены внутри некоторых функций и срабатывают при их вызове. Давайте взглянем:
cot_die_message()
cot_load_structure()
cot_parse()
cot_generate_usertags()
cot_outputfilters()
(уже описывался выше).Кроме перечисленных, в системе присутствует еще большое количество хуков, особенно если вы используетет дополнительные модули или плагины. Для получения полного списка работающих на данной странице хуков в порядке их применения, используйте специальный тег {FOOTER_HOOKS}, вставив его в шаблон footer.tpl. Замечание: этот хук работает только при включенном режиме отладки в файле datas/config.php:
$cfg['debug_mode'] = true;
(Note: тег {FOOTER_HOOKS} доступен для использования начиная с версии 0.9.6)
Поговорим немного о правилах именования хуков. Большинство имен хуков состоит из нескольких слов разделенных точкой. Например:
Это не просто для удобства чтения, но и имеет логический смысл. Первое слово обычно описывает расширение или ту часть системы из которой он вызывается. Например 'users' подразумевает модуль пользователей, или 'header' говорит о заголовке страницы. Это главная подсказка при поиске точки вызова в реальном коде. Вторая часть обычно указывает на часть или режим того или иного расширения, для примера 'users.register' значит, что хук срабатывает при регистрации пользователя, более того это часто значит, что такой хук можно найти в одноименном файле, в данном случае — users.register.php. В терминах MVC можно считать, что это контролер для конкретного расширения. Далее идет строка указывающая на событие или действие, а так же его состояние или место нахождение в коде (first, last, loop, etc.). В приведенном примере строка 'add.done' говорит нам о том, что новый пользователь добавлен (событие) успешно (состояние). В терминах MVC событие/состояние может именем метода.
Таким образом, по имени хука можно сделать выводы о файле в котором расположен код-обработчик и той части кода из которого он вызывается. Поэтому рекомендуется придерживаться этих правил наименования, при разработке собственных дополнений. Ниже мы поговорим об этом подробнее.
Несколько обособлено стоят повторяющиеся (или циклические) хуки. Имя таких хуков как правил оканчивается словом '.loop', например 'forums.topics.sections.loop'. В отличае от обычных хуков, которые как правило вызываются один раз, циклические хуки вызываются неоднократно по числу итераций в определенном цикле. Наиболее чайтый случай применения таких хуков это вызов внутри скрипта по обработке результатов SQL запроса, когда хук вызывается для каждой строки результатов выборки.
Обработчик события (или в терминах Cotonti — хук) это PHP файл в папке расширения, имя которого согласуется с именем хука. Это не жесткое требование, но рекомендуемое к выполнению правило, как пример файл myext.page.edit.update.done.php в котором содержится код обработчика хука page.edit.update.done.
Примерный шаблон файла-обработчика представлен ниже:
<?php /* ==================== [BEGIN_COT_EXT] Hooks=page.tags Tags=page.tpl:{PAGE_MYEXT_TAG1},{PAGE_MYEXT_TAG2} Order=10 [END_COT_EXT] ==================== */ defined('COT_CODE') or die('Wrong URL'); // Hook handler code goes here
Для начала рассмотрим заголовок файла (это блок которй заключен внутри специальных маркеров BEGIN_COT_EXT и END_COT_EXT). Главным и единственным обязательным параметром является ключ Hooks, который задает список хуков обрабатываемых данным файлом. Один файл может быть назначен обработчиком нескольких хуков. В таком случае в ключе задается список хуков, разделенных запятыми. Остальные настройки (ключи) опциональны и могут быть опущены.
Ключ Tags используется для описания дополнительных тегов, назначаемых в процессе обработки. Этот ключ используется в качестве информационного — для отображения в админ-панеле списка дополнительных тегов и имен шаблонов в которых они используются.
На один хук различными расширениями может быть назначено несколько обработчиков. В таких случаях, иногда, полезно иметь возможность задать порядок вызова обработчиков. Для этой цели используется ключ Order, определяющий порядок вызова обработчика. Число определяющее порядок обычно находится в диапазоне 1-99. В первую оччередь выполняются обработчики чей порядковый номер меньше, т.е. в порядке возрастания номеров. Если параметр Order не задан, обработчику будет присвоен порядковый номер по умолчанию — 10.
Что же мы можем сделать используя обработчики? Да почти все что угодно! Вот несколько простеньких примеров:
Важная вещь, о которой стоит упомянуть это область видимости. Исторически Cotonti использует процедурный стиль выполнения скрипта, и большая часть хуков определена в глобальной области видимости. Поэтому в большинстве случаев вам не надо предпринимать дополнительных усилий. Однако есть и такие хуки, которые вызываются внутри функций, в таких случаях вам надо позаботится о доступе к глобальным переменным внутри этой функции, используя ключевое слово global
. Наиболее часто используемые переменные это: $cfg, $usr, $db, $id, $strucutre, $t. Сейчас не будем рассматривать их назначение, т.к. это тема отдельной статьи.
Обратите внимание, что с версии 0.9.15 все наиболее востребованные глобальные переменные ($cfg, $usr, $db, $id, $strucutre и пр.) доступны через специальный «фасад»-класс Cot
. Таким образом нет необходимости использовать явное указание переменных в списке global
, а можно обратиться к ним напрямую через свойство объекта: Cot::$cfg
(например). Полный список переменных доступных через «фасад» следующий: $cache, $cfg, $cot_extrafields, $db, $db_x, $env, $L, $out, $R, $structure, $sys, $usr.
Основной совет начинающим разработчикам расширений для Cotonti —начните с изучения кода. Если вы хотите знать как писать плагины — посмотрите на код некоторых из них (среди них есть очень простые и понятные даже для начинающих). Если вы хотите знать как изменить поведение той или иной части — найдите код, который за нее отвечает, посмотрите где определены ближайшие точки вызова хуков и проанализируйте что происходит в этом куске кода. Cotonti написан в простой и понятной форме и код исполняется достаточно линейно, поэтому можно быстро в нем разобраться. Как только вы разберете основной алгоритм выполнения, вы с легкостью сможете менять его. Для написания более сложных плагинов вам потребуется иметь дело с несколькими хуками и обработчиками, но это уже будет не намного сложней чем начать..
В некоторых случаях вам даже не надо поробно изучать код вызова для написания своего обработчика. Как пример, можно привети добавление нескольких новых тегов в шаблон заголовка страницы или вывести какую либо информацию из БД.
Под модулем здесь понимается любое расширение для Cotonti. После того, как вы изучили, как работать с хуками и писать для них свой обработчик — самое время позаботится о других разработчиках, которые, возможно, захотят дополнить ваше расширение. И самый просто вариант это добавить выхов хуков в местах наиболее вероятного расширения, точно так же как это делает ядро системы:
/* === Hook === */ foreach (cot_getextplugins('myext.hook.name') as $pl) { include $pl; } /* ============ */
Заменяем строку 'myext.hook.name' на имя нашего хука (помните описанные выше правила именования? ) и почти готово. Возможно вы заметито, что данный код можно записать в одну строку, но мы рекомендуем использовать именно приведенную (6-ти строчную) форму записиruct для того, чтобы он был выделен среди прочего кода, и стороннему разработчику было проще найти точку расширения.
Все, для чего нужна здесь функция cot_getextplugins()
это получить массив с именами файлов обработчиков указанного хука. Далее просто подключаем файл через include или include_once.
Несколько более громоздким выглядит код в случае, когда надо вызывать обработчик на каждом шаге цикла:
/* === Хук - часть1 : установка === */ $extp = cot_getextplugins('myext.some.loop'); /* ============ */ // Цикл может быть любым foreach/while/do foreach ($items as $item) { // некоторый код /* === Хук - часть2 : вызов обработчика === */ foreach ($extp as $pl) { include $pl; } /* ============ */ // еще какой-то код }
Суть кода вынести вызов функции cot_getextplugins()
из цикла для ускорения выполнения скрипта.
Рекомендуется создавать точки расширения (хуки) для любого значитального события в вашем модуле, которое потенциально может быть расширен, как правило это сбытия следующих типов: create/update/delete/display.
В зависимости от запрошенного на сайте URL обработка данных для вывода страницы может идти несколько разными путяни. Ниже приведен упорядоченный список вызова основных хуков, для хороктерных случаев::
Примечание: элементы списка помеченные знаком "(*)" означают, многократный последовательный взов хука. Хуки помещенные в квадратные скобки "[]" подразумевают возможный вызов, т.к. их список и конкретные имена зависят от верси ядра и набора установленных расширений. Хуки отмеченные жирным шрифтом являются системными и описаны выше.above).