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

Использование 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; 

Чтобы оставить сообщение, авторизуйтесь, или войдите с помощью:
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 все отлично работает ....
Главная   ·   Модули для 1С-Битрикс   ·   Типовые услуги   ·   Форум   ·   Блог   ·   Контакты
Рейтинг@Mail.ru