Wiki Bitrix

Сниппеты getMap()

getMap используется для описания схемы БД в ORM. Сниппеты ниже следует использовать в return […] Entity\DataManager::getMap()

Сериализация при сохранении и десериализация при выборке

new Entity\TextField('DEBT_DATA_RAW', [
  'save_data_modification' => function () {
    return [
      function ($value) {
        return serialize($value);
      }
    ];
  },
  'fetch_data_modification' => function () {
    return [
      function ($value) {
        return unserialize($value);
      }
    ];
  }
]),

ID

new Entity\IntegerField('ID', [
  'primary' => true,
  'autocomplete' => true
]),

GUID

new Entity\StringField('PARTNER_GUID', [
  'primary' => true,
  'size' => 36
]),

Datetime

new Entity\DatetimeField('DATE_CREATED', []),
new Entity\DatetimeField('DATE_UPDATED', [
  'default_value' => new \Bitrix\Main\Type\Datetime
]),

Булево значение да/нет

new Entity\BooleanField('ACTIVE', [
  'values' => ['Y', 'N'],
  'default_value' => 'Y'
]),

ReferenceField

Привязка одного элемента к другому, или внешний ключ на другую сущность.

Привязка к инфоблоку ElementTable по ID, XML_ID, NAME

Так выглядит привязка к элементу инфоблока с номером 51, по XML_ID:

new Entity\ReferenceField(
  'PARTNER',
  'Bitrix\Iblock\ElementTable',
  [
    '=this.PARTNER_GUID' => 'ref.XML_ID',
    '=ref.IBLOCK_ID' => new \Bitrix\Main\DB\SqlExpression('?i', 51)
  ]
),

Вообще, возможно привязываться таким способом к ID, XML_ID, NAME и другим полям, описанным в ElementTable. Однако если для привязки в «привязываемом элементе» используется свойство, это будет сделать проблематично (см ниже).

Привязка к инфоблоку ElementTable по свойству

Допустим, есть элемент инфоблока с номером ID, и мы создаем схему этой сущности. В другом инфоблоке есть элемент, у которого заведено свойство TENDER_ID, который ссылается на описываемую сущность:

tenderrequest.php
new Entity\ReferenceField(
  '1C',
  'Vendor\Logistic\Orm\Arrival\OneSPropsTable',
  [
    '=this.ID' => 'ref.TENDER_ID',
  ]
),

Как сделать привязку через getMap()? Дело осложняется тем, что свойства представляют собой отдельные записи в таблице b_iblock_element_property, поэтому еще необходимо самообъединение таблиц. Все эти свойства можно получить через запрос:

SELECT * FROM b_iblock_element_property WHERE IBLOCK_ELEMENT_ID = 4994277;

Эту проблему я решил через SQL представление:

DROP VIEW IF EXISTS `vendor_logistic_1c_info`;
 
CREATE VIEW `vendor_logistic_1c_info` AS
 
SELECT
prim.VALUE_NUM AS `TENDER_ID`,
prop_1.VALUE AS `KOD_RS`,
prop_2.VALUE AS `NAME_RS`,
prop_3.VALUE AS `ZAKAZ`,
prop_4.VALUE AS `ITEM_NUM`
FROM `b_iblock_element_property` AS `prim`
JOIN `b_iblock_element_property` AS `prop_1` ON (prim.IBLOCK_ELEMENT_ID = prop_1.IBLOCK_ELEMENT_ID AND prop_1.IBLOCK_PROPERTY_ID = 279)
JOIN `b_iblock_element_property` AS `prop_2` ON (prim.IBLOCK_ELEMENT_ID = prop_2.IBLOCK_ELEMENT_ID AND prop_2.IBLOCK_PROPERTY_ID = 280)
JOIN `b_iblock_element_property` AS `prop_3` ON (prim.IBLOCK_ELEMENT_ID = prop_3.IBLOCK_ELEMENT_ID AND prop_3.IBLOCK_PROPERTY_ID = 281)
JOIN `b_iblock_element_property` AS `prop_4` ON (prim.IBLOCK_ELEMENT_ID = prop_4.IBLOCK_ELEMENT_ID AND prop_4.IBLOCK_PROPERTY_ID = 282)
WHERE prim.IBLOCK_PROPERTY_ID = 278;
 
-- демонстрация работы
SELECT sql_no_cache * FROM vendor_logistic_1c_info WHERE TENDER_ID = 4979188;

Для быстрой работы запроса используется prim.VALUE_NUM AS `TENDER_ID` (хранит тип DECIMAL), а не prim.VALUE (тип VARCHAR).

onesprops.php
namespace Vendor\Logistic\Orm\Arrival;
 
use \Bitrix\Main\Entity;
 
class OneSPropsTable extends Entity\DataManager {
 
  public static function getTableName() {
    return 'vendor_logistic_1c_info';
  }
 
  public static function getMap() {
 
    return [
      new Entity\StringField('ITEM_NUM', ['primary' => true]),
      new Entity\IntegerField('TENDER_ID'),
      new Entity\StringField('KOD_RS'),
      new Entity\StringField('NAME_RS'),
      new Entity\StringField('ZAKAZ'),
    ];
 
  }
 
}

Привязка к пользователю UserTable

new Entity\ReferenceField(
  'USER',
  'Bitrix\Main\UserTable',
  ['=this.USER_ID' => 'ref.ID']
),

ExpressionField

Удобно задавать алиасы, чтобы названия столбцов были читаемые. %s рекоментуется использовать везде, чтобы работала фильтрация, заданная перечислением «=PARTNER_NAME» ⇒ […]

new Entity\ExpressionField('PARTNER_NAME', '%s', 'PARTNER.DETAIL_TEXT'),

Более продвинутый вариант, когда данные нужно дополнительно обрабатывать:

new Entity\ExpressionField('UNLOADING_DATE', '%s', 'PROPS.PROPERTY_241',      // Дата разгрузки
  [
    'save_data_modification' => function () {
      return [
        function ($value) {
          return serialize($value);
        }
      ];
    },
    'fetch_data_modification' => function () {
      return [
        function ($value) {
          return unserialize($value);
        }
      ];
    }
  ]
),

Форматирование даты:

new Entity\ExpressionField('ACTIVE_FROM', "DATE_FORMAT(ACTIVE_FROM, '%%d.%%m.%%Y %%H:%%m:%%S')"),
Фильтр по дате, если она определена таким образом: new Entity\ExpressionField(«LOADING_DATE», «%s», «PROPS.PROPERTY_238») работать не будет, связано с форматированием даты в другом формате. Следует использовать так: «=PROPS.PROPERTY_238»