партнер компании 1с-битрикс
сайт фрилансера Сергея Эстрина
Войти как пользователь
Вы можете войти на сайт, если вы зарегистрированы на одном из этих сервисов:
Универсальная галерея - модуль для битрикс
В этой статье я покажу на примерах один из вариантов работы с событиями модуля highload-инфоблоков. Хотя это и не обязательно, стараясь соответствовать новым веяниям в битриксопрограммировании, я использовал функции с пространствами имен (если считаете, что сделал я что-то неправильно, пожалуйста, отпишитесь в комментариях). По задумке, в следующих примерах "Partner" должно быть заменено на ваш идентификатор партнера в marketplace (если он у вас есть, либо используйте любое слово), а "Myentity" - на название сущности вашего highload-инфоблока (то, что вы указываете при его создании).
[spoiler]
Использование OnBeforeAdd, OnBeforeUpdate

События OтBeforeAdd, OnBeforeUpdate вызываются до проверки полей на правильность. В их обработчиках еще возможна модификация результата - для этого функция должна вернуть переменную типа "\Bitrix\Main\Entity\EventResult". Также возможна проверка полей на правильность и возврат сообщения об ошибке.


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnBeforeUpdate''\Partner\Myentity\OnBeforeAddUpdate');
$eventManager->addEventHandler('''MyentityOnBeforeAdd''\Partner\Myentity\OnBeforeAddUpdate');

function 
OnBeforeAddUpdate(\Bitrix\Main\Entity\Event $event)
{
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];
   if(!
$ID)
      return;

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
$eventType $event->getEventType();

   
$arFields $event->getParameter("fields");

   
$price = ...
   
   
$error = ...
   
   
$result = new \Bitrix\Main\Entity\EventResult();

   if(
$error) {

      
$arErrors = Array();
      
$arErrors[] = new \Bitrix\Main\Entity\FieldError($entity->getField("MYFIELD"), "Ошибка в поле MYFIELD");
      
$result->setErrors($arErrors);

   } else {

      
$arFields["UF_AVG_PRICE"] = $price;
      
$event->setParameter("fields",$arFields);
   
      
$changedFields = Array();
      
$changedFields["UF_AVG_PRICE"] = $price;
      
$result->modifyFields($changedFields);
       
//$result->unsetFields($arUnsetFields);

   
}
   
   }

   return 
$result;

}

Использование OnAdd, OnUpdate

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


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnUpdate''\Partner\Myentity\OnAddUpdate');
$eventManager->addEventHandler('''MyentityOnAdd''\Partner\Myentity\OnAddUpdate');

function 
OnAddUpdate(\Bitrix\Main\Entity\Event $event)
{
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
$eventType $event->getEventType();

   
$arParameters $event->getParameters();
   
//$event->setParameters($arParameters);

   //$arFields = $event->getParameter("fields");
   //$event->setParameter("fields",$arFields);

}

Использование OnAfterAdd, OnAfterUpdate

Эти события вызываются после добавления и обновления записей в highload-инфоблоках. В данном примере статическая переменнная используется для предотвращения вечного цикла из-за того, что внутри обработчика вызывается функция Update, которая должна повторно запустить обработчик. Использование такого подхода может быть оправдано в каких-то случаях, хотя обычно бывает достаточно OnAdd, OnUpdate.


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnAfterUpdate''\Partner\Myentity\OnAfterAddUpdate');
$eventManager->addEventHandler('''MyentityOnAfterAdd''\Partner\Myentity\OnAfterAddUpdate');

function 
OnAfterAddUpdate(\Bitrix\Main\Entity\Event $event)
{
 
   static 
$bHandlerStop;
   if(
$bHandlerStop===true)
      return;
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];
   if(!
$ID)
      return;

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
$eventType $event->getEventType();

   
$arParameters $event->getParameters();
   
//$event->setParameters($arParameters);

   //$arFields = $event->getParameter("fields");
   //$event->setParameter("fields",$arFields);

   
$bHandlerStop true;
   
$result $entityDataClass::update($ID, Array("UF_AVG_PRICE"=>2.0));
   
$bHandlerStop false;

}

Использование OnBeforeDelete

Событие OnBeforeDelete вызывается перед удалением элемента и может быть использовано для отмены удаления (для этого нужно сгенерировать объект типа \Bitrix\Main\Entity\EntityError и добавить его в список ошибок с помощью метода \Bitrix\Main\Entity\EventResult\setError).


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnBeforeDelete''\Partner\Myentity\OnBeforeDelete');

function 
OnBeforeDelete(\Bitrix\Main\Entity\Event $event)
{
 
   
// All $event functions /bitrix/modules/main/lib/event.php
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
$result = new \Bitrix\Main\Entity\EventResult();

   if(
$ID==15) {

      
$arErrors = Array();
      
$arErrors[] = new \Bitrix\Main\Entity\EntityError("Нельзя удалить запись с ID=".$ID);
      
$result->setErrors($arErrors);

   }

   return 
$result;

}

Использование OnDelete

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


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnDelete''\Partner\Myentity\OnDelete');

function 
OnDelete(\Bitrix\Main\Entity\Event $event)
{
 
   
// All $event functions /bitrix/modules/main/lib/event.php
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
define("ERROR_EMAIL""my@email.ru"); 
   
\SendError("Запись с ID=$ID будет удалена\n\n");

}

Использование OnAfterDelete

Событие OnAfterDelete вызывается после удаления элемента хайлоадблока.


namespace Partner\Myentity;


$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('''MyentityOnAfterDelete''\Partner\Myentity\OnAfterDelete');

function 
OnAfterDelete(\Bitrix\Main\Entity\Event $event)
{
 
   
// All $event functions /bitrix/modules/main/lib/event.php
      
   
$ID $event->getParameter("id");
   if(
is_array($ID))
      
$ID $ID["ID"];

   
$entity $event->getEntity();
   
$entityDataClass $entity->GetDataClass();

   
define("ERROR_EMAIL""my@email.ru"); 
   
\SendError("Запись с ID=$ID была удалена\n\n");

}

Функции \Bitrix\Main\Entity\Event

Полный список функций \Bitrix\Main\Entity\Event вы можете найти в файле /bitrix/modules/main/lib/event.php, я же поясню лишь значение некоторых:


$arFields $event->getParameter("fields"); // получаем список полей   

$event->setParameter("fields",$arFields); // обновляем список полей  
$entity $event->getEntity(); // получаем объект сущности 
$eventType $event->getEventType(); // получаем тип события (например, "MyentityOnUpdate") 
$moduleId $eventType $event->getModuleId(); // получаем код модуля

Объекты ошибок

Есть 2 типа ошибок - ошибка в каком-то поле и общая ошибка (ошибка сущности). Для их генерации существуют классы \Bitrix\Main\Entity\FieldError и \Bitrix\Main\Entity\EntityError соответственно.


$entity $event->getEntity();

 
$result = new \Bitrix\Main\Entity\EventResult(); 
 
$arErrors = Array();
$arErrors[] = new \Bitrix\Main\Entity\FieldError($entity->getField("MYFIELD"), "Ошибка в поле MYFIELD");
$arErrors[] = new \Bitrix\Main\Entity\EntityError("Общая ошибка");
$result->setErrors($arErrors);

return 
$result;
См. также сниппеты "События ORM/хайлоадблоков" на сайте estrin.pw

Чтобы оставить сообщение, авторизуйтесь, или войдите с помощью:
24.02.2015 23:47:31
Сергей, а можете для чайника в основах работы ядра D7 рассказать в какие файлы/папки весь код помещать?

например, я создаю свой какой-то модуль. В нем мне нужно создать обработчик, который будет записывать в xml_id значение id элемента (очень печально, но именно по полю UF_XML_ID осуществляется связка свойств типа "Справочник" - так мне объяснили в техподдержке).

Я понимаю, что нужно использовать OnAfterAdd и OnAfterUpdate
но вот как и куда эти обработчики поместить - что-то я потерялся:(


и как RegisterModuleDependences(....); в инсталляции модуля правильно прописать
25.02.2015 15:09:46
но вот как и куда эти обработчики поместить - что-то я потерялся:(
Если делать как в указанных здесь примерах, то используйте пространства имен php (php namespaces). Чтобы было понятно: в данных примерах используются функции без классов, но с пространствами имен. Классы тоже могут быть в пространствах имен. Особенность пространств имен такова, что каждое пространство может быть только в отдельном файле. Если вы вставляете ваши обрабочики в init.php, то размещайте ваши файлы с пространствами имен, например, в папке /bitrix/php_interface/lib/ или /local/php_interface/lib/ и подключайте в init.php с помощью include. Но, справедливости ради стоит заметить, что пространства имен - это штуки из php, никакого отношения к битриксу или d7 они не имеют.

Если же вы пишите модуль, то вместо

$eventManager->addEventHandler

используйте

$eventManager->registerEventHandlerCompatible("module","event","module2","class","function");

(Это аналог старого RegisterModuleDependences)
25.02.2015 15:33:36
Имеется у меня модуль с ID = vertical.bhpro

в файле /install/index.php в  блоке "DoInstall" после регистрации в системе самого модуля (RegisterModule(self::MODULE_ID) )
прописываю:

$eventManager \Bitrix\Main\EventManager::getInstance();

$eventManager->registerEventHandlerCompatible("highloadblock","PartsOnAfterUpdate",self::MODULE_ID,"PartsTable","OnAfterAddUpdate");
в файле include модуля прописываю:

CModule::AddAutoloadClasses(

 
'vertical.bhpro',
 array(
 
'PartsTable' => 'lib/parts.php',
 )
);
и в самом файле прописываю:

<?php

namespace Vertical\Parts;

use 
Bitrix\Main\Entity;
use 
Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__);

class 
PartsTable extends Entity\DataManager
{

 function 
OnAfterAddUpdate(\Bitrix\Main\Entity\Event $event)
 {

 static 
$bHandlerStop;
 if(
$bHandlerStop===true)
 return;

 
$ID $event->getParameter("id");
 if(
is_array($ID))
 
$ID $ID["ID"];
 if(!
$ID)
 return;

 
$eventType $event->getEventType();

 
$arParameters $event->getParameters();
 
//$event->setParameters($arParameters);

 //$arFields = $event->getParameter("fields");
 //$event->setParameter("fields",$arFields);

 
$bHandlerStop true;
 
$result \PartsTable::update($ID, Array("UF_XML_ID"=>$ID));
 
$bHandlerStop false;

 }
}
Удаляю свой модуль из системы - устанавливаю заново. Пробую сохранить изменения в записи хайлоада - ничего не меняется:(
25.02.2015 15:53:51
Может быть потому что

$eventManager->registerEventHandlerCompatible("highloadblock",

С addEventHandler по какой-то неведомой мне причине не работает, если указать highloadblock, а работает только с пустой строкой вместо этого, может быть с registerEventHandlerCompatible так же? А может что-то с немспейсами напутали, сейчас не могу сообразить... Или попробуйте вместо registerEventHandlerCompatible просто registerEventHandler, я правда пока точно не знаю какая между ними разница.

P.S. Отпишитесь плиз если получится, мне тоже интересно.
25.02.2015 16:35:24
тоже не идет. буду ждать ответа техподдержки
08.03.2015 07:54:38
к сожалению, техподдержка не помогли. а вот через init.php все отлично работает ....