Несмотря на то что со стороны базы данных сущности описываются в разных таблицах, программистам удобнее работать с комплексными структурами наиболее качественно описывающими сущность.

Для упрощения работы программистов со стороны платформы часто предоставляются специальные структуры которые могут облегчить жизнь.

Полное описание сущности

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

Обычно в таблицах они имеют ключи OWNER_TYPE_ID (для идентификатора типа) и OWNER_ID (для идентификатора элемента), иногда встречаются и такие поля как ENTITY_ID (мнемонический код типа) и ELEMENT_ID (идентификатора элемента).

В системе существует определенное количество системных сущностей и для каждой сущности закреплено мнемонический код, ее порядковый номер и комплексный префикс.

Мнемонические коды и порядковые номера представлены в классе CCrmOwnerType.

Константы порядковых идентификатор в названии имеют только название сущности, в то время как к мнемоническим кодам добавляется постфикс Name.

Например: порядковый номер лида находится в константе \CCrmOwnerType::Lead, а его мнемонический код в константе \CCrmOwnerType::LeadName. Не имеет смысла приводить полный перечень таких кодов, ознакомиться с доступными в вашей версии модуля вы можете самостоятельно.

С появлением модуля “Корзина” (recyclebin) и “Машинное обучение” (ml) были введены специальные код Suspended* (для каждого типа сущности) и ScoringName которые являются техническими кодами для обозначения элементов.

Помимо порядкового номера и мнемонического кода существуют так же комплексные префиксы. Префиксы необходимо для того чтобы в одном поле можно было хранить идентификаторы разных сущностей. Например: для создания поля которое должно было бы хранить и контакты и компании потребовалось либо хранить структуру данных либо отказаться от этой идеи в пользу двух полей.

Для работы с сокращенными названиями (с использованием комплексных префиксов) существует класс CCrmOwnerTypeAbbr и механизм хранения префиксов аналогичен механизму хранения мнемонических кодов сущностей.

API

Получение ссылок на страницы сущностей

Для получения ссылок на страницы сущностей используются методы: \CCrmOwnerType::GetEntityShowPath($typeID, $ID, $bCheckPermissions = false, array $options = null) и \CCrmOwnerType::GetEntityEditPath($typeID, $ID, $bCheckPermissions = false, array $options = null), который возвращают относительные ссылки на просмотр и редактирование сущностей.

В обоих методах: $typeID - идентификатор типа сущности $ID - идентификатор сущности $bCheckPermissions - флаг необходимости проверки прав. В случае если он установлен в true и у пользователя нет прав, вернется пустая строка. $options - массив дополнительных опций для формирования ключей.

На данный момент $options обрабатывает только один ключ ENABLE_SLIDER. В определенный момент, модуль допускал 2 варианта отображения карточек: устаревший “show” и актуальный “detail”. В настоящее время мы рекомендуем не изменять параметры выдачи ссылок и оставить доп.опции без изменений.


$entityTypeId = \CCrmOwnerType::Lead;
$entityId = 123;

/**
 * Display: /crm/lead/details/123/
 */
echo \CCrmOwnerType::GetEntityShowPath( $entityTypeId, $entityId );

/**
 * Display: /crm/lead/details/123/?init_mode=edit
 */
echo \CCrmOwnerType::GetEntityEditPath( $entityTypeId, $entityId );

Получение ссылки на страницы списка

За предоставление ссылок отвечает метод \CCrmOwnerType::GetListUrl($typeID, $bCheckPermissions = false). Его механика аналогична методам получения ссылки на карточки элементов.

$entityTypeId = \CCrmOwnerType::Lead;
/**
 * Display: /crm/lead/list/
 */
echo \CCrmOwnerType::GetListUrl( $entityTypeId );

Проверка существования типа

/**
 * Checked type
 * @var int
 */
$typeID = 1234;

/**
 * Is type defined? 
 * @var bool
 */
$isDefinedType = \CCrmOwnerType::IsDefined($typeID);

Является ли тип основной сущностью


/**
 * @var bool
 */
$isEntity = \CCrmOwnerType::IsEntity( \CCrmOwnerType::Lead );

Конвертация мнемонического кода в ID

/**
 * @see CCrmOwnerType::*
 * @var integer
 */
$entityTypeId = \CCrmOwnerType::ResolveID( \CCrmOwnerType::LeadName ); 

Конвертация ID в мнемонический код

/**
 * @see CCrmOwnerType::*Name
 * @var string
 */
$entityTypeName = \CCrmOwnerType::ResolveName( \CCrmOwnerType::Lead ); 

Получение префикса по коду сущности

/**
 * @see CCrmOwnerTypeAbbr::*Name
 * @var string
 */
$prefix = \CCrmOwnerTypeAbbr::ResolveByTypeID( \CCrmOwnerType::Lead ); // display: L

Обработка комплексного префикса

Часто возникает необходимость разобрать составные названия на идентификатор сущности и идентификатор типа сущности. За это отвечает метод \CCrmOwnerType::ParseEntitySlug($slug)

/**
 * @var array
 */
$parsed = \CCrmOwnerType::ParseEntitySlug('L_1');

var_dump($parsed);
/*
array(2) {
  ["ENTITY_TYPE_ID"]=>
  int(1)
  ["ENTITY_ID"]=>
  int(1)
}
*/

Коммуникационные поля

Исторически для описания таких полей как Телефон, Email, Сайт, IM используется структура Коммуникационные поля (crm_multifield). Все данные сохраняются в таблице b_crm_field_multi

Поле Тип данных
ID int(18)
ENTITY_ID varchar(16)
ELEMENT_ID int(18)
TYPE_ID varchar(16)
VALUE_TYPE varchar(50)
COMPLEX_ID varchar(100)
VALUE varchar(250)

ID - уникальный идентификатор значения ENTITY_ID - мнемонический код сущности ELEMENT_ID - идентификатор сущности к которому относится значение TYPE_ID - симв.код сохраняемого значения VALUE_TYPE - подтип сохраняемого значения COMPLEX_ID - комплексный идентификатор. Состоит из полей TYPE_ID и VALUE_TYPE объединенных символом подчеркивания VALUE - сохраняемое значение.

Пример: сохраненная почта some@email как рабочая почта для лида ID:123

Поле Значение
ID 12345
ENTITY_ID LEAD
ELEMENT_ID 123
TYPE_ID EMAIL
VALUE_TYPE HOME
COMPLEX_ID EMAIL_HOME
VALUE some@email

За работу с множественными полями отвечает класс CCrmFieldMulti.

Список поддерживаемых на данный момент полей представлен в виде констант, аналогично с \CCrmOwnerType: \CCrmFieldMulti::PHONE, \CCrmFieldMulti::EMAIL, \CCrmFieldMulti::WEB, \CCrmFieldMulti::IM

API

Полезные методы

Проверка доступности типа

Проверка доступности типа осуществляется методом \CCrmFieldMulti::IsSupportedType($typeID), который возвращает true, в случае если данный тип обрабатывается классом.


/**
 * @var string
 */
$typeID = \CCrmFieldMulti::PHONE;

/**
 * @var boolean
 */
$IsSupportedType = \CCrmFieldMulti::IsSupportedType($typeID);

Список доступных типов

Получить список доступных системных типов можно через статический метод \CCrmFieldMulti::GetEntityTypeInfos()

var_dump(\CCrmFieldMulti::GetEntityTypeInfos());
/*
array(4) {
  ["PHONE"]=>
  array(1) {
    ["NAME"]=>
    string(14) "Телефон"
  }
  ["EMAIL"]=>
  array(1) {
    ["NAME"]=>
    string(6) "E-mail"
  }
  ["WEB"]=>
  array(1) {
    ["NAME"]=>
    string(8) "Сайт"
  }
  ["IM"]=>
  array(1) {
    ["NAME"]=>
    string(20) "Мессенджер"
  }
}
*/

Получение структуры описывающий типы

Получить список доступных системных типов можно через статический метод \CCrmFieldMulti::GetEntityTypes(). Метод возвращает ассоциативную иерархию из TYPE и VALUE_TYPE значений.

var_dump(\CCrmFieldMulti::GetEntityTypes());

Усеченный пример результата вызова:

array(4) {
  ["PHONE"]=>
  array(7) {
    ["WORK"]=>
    array(4) {
      ["FULL"]=>
      string(29) "Рабочий телефон"
      ["SHORT"]=>
      string(14) "Рабочий"
      ["ABBR"]=>
      string(7) "Раб."
      ["TEMPLATE"]=>
      string(41) "<a href="callto:#VALUE#">#VALUE_HTML#</a>"
    }
    ["MOBILE"]=>
    array(4) {
      ["FULL"]=>
      string(33) "Мобильный телефон"
      ["SHORT"]=>
      string(18) "Мобильный"
      ["ABBR"]=>
      string(7) "Моб."
      ["TEMPLATE"]=>
      string(41) "<a href="callto:#VALUE#">#VALUE_HTML#</a>"
    }
    ...
  }
}

Получить тип значения по-умолчанию

Для получения типа значения по-умолчанию используется статический метод \CCrmFieldMulti::GetDefaultValueType($entityTypeID), который всегда возвращает тип значения по-умолчанию для указанного типа.

echo \CCrmFieldMulti::GetDefaultValueType( \CCrmFieldMulti::PHONE ); // WORK

Списочные методы

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

CCrmFieldMulti::GetListEx($arOrder = array(), $arFilter = array(), $arGroupBy = false, $arNavStartParams = false, $arSelectFields = array(), $arOptions = array())

Принципы фильтрации и общие методы работы изложены в документации к методу CIblockElement::GetList.

Добавление

За добавление нового множественного поля отвечает нестатический метод Add($arFields, array $options = null).

$arFields - ассоциативный массив описания значения. $options - массив дополнительных опций при обработке. В настоящее время принимается только одна опция ENABLE_NOTIFICATION которая дает понять механизму что нужно сообщить контроллеру дубликатов что поля изменились.

Пример добавления нового рабочего телефонного номера:

/**
 * @var array
 */
$multiField = [
    'ENTITY_ID'  => \CCrmOwnerType::LeadName,
    'ELEMENT_ID' => 123,
    'TYPE_ID'    => 'PHONE',
    'VALUE_TYPE' => 'WORK',
    'VALUE'      => '+7 (666) 555-44-33'
];

$multi = new \CCrmFieldMulti();

$rowId = $multi->Add(
    $multiField,
    [
        'ENABLE_NOTIFICATION' => true,
    ]
);

if ( !$rowId )
{
    // Error when add. You can find:
    // $GLOBALS['APPLICATION']->LAST_ERROR;
}

Редактирование

За редактирование значения множественного поля отвечает нестатический метод Update($ID, $arFields, array $options = null).

$ID - идентификатор удаляемого телефона. $arFields - ассоциативный массив описания значения. $options - массив дополнительных опций при обработке. В настоящее время принимается только одна опция ENABLE_NOTIFICATION которая дает понять механизму что нужно сообщить контроллеру дубликатов что поля изменились.

/**
 * @var array
 */
$multiField = [
    'TYPE_ID'    => 'PHONE',
    'VALUE_TYPE' => 'WORK',
    'VALUE'      => '+7 (666) 555-44-33'
];

/**
 * @var integer
 */
$rowId = 123;

$multi = new \CCrmFieldMulti();

$rowId = $multi->Update(
    $rowId,
    $multiField,
    [
        'ENABLE_NOTIFICATION' => true,
    ]
);

if ( !$rowId )
{
    // Error when add. You can find:
    // $GLOBALS['APPLICATION']->LAST_ERROR;
}

Удаление

Удаление телефонного номера

Если вы знаете ID удаляемого телефона, вы можете воспользоваться нестатическим методом Delete для удаления CCrmFieldMulti::Delete($ID, array $options = null).

$ID - идентификатор удаляемого телефона. $options - массив дополнительных опций при обработке. В настоящее время принимается только одна опция ENABLE_NOTIFICATION которая дает понять механизму что нужно сообщить контроллеру дубликатов что поля изменились.

/**
 * @var integer
 */
$rowId = 1234;

$multi = new \CCrmFieldMulti();

$clearResult = $multi->Delete(
    $rowId,
    [
        'ENABLE_NOTIFICATION' => true,
    ]
);

if ( $clearResult === false )
{
    // Incorrect parameters
}
else
{
    // Deleted rows count
    var_dump($clearResult->AffectedRowsCount());
}

Удаление всех множественных полей элемента

Осуществляется нестатическим методом DeleteByElement($entityId, $elementId)

Пример: удаление всех множественных полей лида с ID:123

$multi = new \CCrmFieldMulti();

$clearResult = $multi->DeleteByElement(
    \CCrmFieldMulti::LeadName,
    123
);

if ( $clearResult === false )
{
    // Incorrect parameters
}
else
{
    // Deleted rows count
    var_dump($clearResult->AffectedRowsCount());
}

Пакетное сохранение

Несмотря на существование точечных методов на добавление, редактирование и удаление элементов для упрощения работы с ними можно использовать пакетный метод, который сам определить необходимые к изменению элементы. За эту работу отвечает нестатический метод SetFields($entityId, $elementId, $arFieldData, array $options = null).

$entityId - мнемонический код изменяемой сущности. $elementId - идентификатор элемента. $arFieldData - массив описывающий изменяемую структуру. $options - не используемый параметр в данный момент.

Пример составления структуры arFieldData:

$arFieldData = [
    'PHONE' => [
        // Add phone
        'n0' => [
            'VALUE_TYPE' => 'WORK',
            'VALUE'      => '8 (800) 200-06-00',
        ],
        // Add another phone
        'n1' => [
            'VALUE_TYPE' => 'HOME',
            'VALUE'      => '+7 (495) 222-22-22',
        ],
        // Delete row with id 123
        '123' => [
            'VALUE' => '',
        ],
        // Change phone with rowId 456
        '456' => [
            'VALUE' => '88002000601',
        ], 
    ],
    'EMAIL' => [
        // Add email
        'n0' => [
            'VALUE_TYPE' => 'WORK',
            'VALUE'      => 'work@email.com',
        ],
        // Delete row with id 567
        '123' => [
            'VALUE' => '',
        ],
    ]
];

Пример использования структуры выше для лида 123

$fieldMulti = new CCrmFieldMulti();
$fieldMulti->SetFields(
    \CCrmOwnerType::LeadName,
    123,
    $arFieldData
);