Документация для разработчиков
Темная тема

Начало работы

Введение


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

У этого подхода есть ряд недостатков:

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

С точки зрения публичного интерфейса доступа к данным об элементе сущности, особенных различий между элементами разных сущностей нет. Общего гораздо больше.

Чтобы унифицировать подход, закрыть перечисленные выше недостатки, в новом API был введён абстрактный класс Bitrix\Crm\Item.

Этот класс содержит в себе Bitrix\Main\ORM\Objectify\EntityObject и имитирует его поведение.

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

Класс воспроизводит интерфейс \ArrayAccess, при обращении к объекту как к массиву, будут вызваны метод get и set.

Коды "общих" полей этого класса основаны на соответствующих кодах полей таблицы элементов смарт-процесса.


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

Это значит, что если у этого объекта не заполнены какие-то данные (не были переданы в select), то и класс не будет иметь к ним доступ.

Именованные методы

Класс имеет набор именованных методов (по аналогии с EntityObject) для работы с состоянием и значениями полей.

Например, метод getStageId вернет строковый идентификатор стадии элемента. Даже если поле называется не STAGE_ID, а STATUS_ID, метод всё равно будет работать.

Аналогично будет работать метод setStageId - он запишет новое значение в поле для стадии, независимо от его кода в таблице элементов.

И так же будет работать метод isChangedStageId. Остальные кейсы, доступные в EntityObject, не реализованы.

Работа с именованными методами реализована через магический метод __call. Некоторые именованные методы реализованы в явном виде.

Вот полный набор методов, доступных для работы с полем "Заголовок" (TITLE):

  • getTitle(): ?string - вернет текущее значение;
  • setTItle(string $title): Item - запишет новое значение;
  • isChangedTitle(): bool - вернет true, если значение поля было изменено.

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


Примеры:

  • getCreatedTime(): ?DateTime
  • getUpdatedTime(): ?DateTime
  • getMovedTime(): ?DateTime
  • getCreatedBy(): ?int
  • getUpdatedBy(): ?int
  • getMovedBy(): ?int
  • getAssignedById(): ?int
  • getOpened(): bool
  • getBegindate(): ?DateTime
  • getClosedate(): ?DateTime
  • getCompanyId(): ?int
  • getContactId(): ?int
  • getStageId(): ?string
  • getCategoryId(): ?int
  • getOpportunity(): ?float
  • getIsManualOpportunity(): bool
  • getTaxValue(): float
  • getCurrencyId(): ?string
  • getOpportunityAccount(): ?float
  • getTaxValueAccount(): ?float
  • getAccountCurrencyId(): ?string
  • getMycompanyId(): ?int
  • getProductRows(): ?ProductRowCollection
  • getClosed(): bool
  • getSourceId(): ?string
  • getSourceDescription(): ?string
  • getWebformId(): ?int

Аналогичным образом можно работать с полями UTM-меток. Хотя значения этих полей не хранятся непосредственно в таблице элементов, к ним есть доступ аналогичным способом из этого класса.


  • getUtmSource(): ?string
  • getUtmMedium(): ?string
  • getUtmCampaign(): ?string
  • getUtmContent(): ?string
  • getUtmTerm(): ?string

Общие методы

Метод Описание С версии
public function __construct(int $entityTypeId, EntityObject 
$entityObject, array $fieldsMap = [], array $disabledFieldNames = [])

  • $entityTypeId - идентификатор типа сущности CRM;
  • $entityObject - orm-объект с данными;
  • $fieldsMap - карта сопоставления полей, где ключ - "общий" код поля (см. публичные константы класса FIELD_NAME_), а значение - код поля из таблицы элементов;
  • $disabledFieldNames - коды полей, которые не должны быть доступны в некоторых методах.
Использовать конструктор напрямую настоятельно не рекомендуется. Для получения объектов необходимо использовать соответствующие методы фабрики.
public function hasField(string $fieldName): bool
Вернет true, если элемент имеет поле с названием $fieldName.
Здесь и далее $fieldName может быть как "общим", так и специфическим для сущности.

Например, hasField('STAGE_ID') и hasField('STATUS_ID') для элемента сущности "Лид" оба вернут true.
public function getDefaultValue(string $fieldName)
Вернет значение по умолчанию для поля $fieldName.
public function get(string $fieldName)
Вернет текущее значение поля $fieldName.
public function set(string $fieldName, $value): self
Запишет новое текущее значение $value у поля $fieldName.
public function reset(string $fieldName): self
Сбросит значение поля $fieldName в его исходное состояние.
public function unset(string $fieldName): self
Запишет пустое значение в поле $fieldName.
public function remindActual(string $fieldName)
Вернет исходное значение поля $fieldName.
public function isChanged(string $fieldName): bool
Вернет true, если поле $fieldName было изменено (текущее значение отличается от исходного).
public function getData(int $valuesType = Values::ALL): array
Вернет массив значений полей элемента, где ключами являются "общие" коды полей, а значениями - значения этих полей, отобранные по маске $valuesType.
$valuesType может принимать значения, описанные в классе \Bitrix\Main\ORM\Objectify\Values:
\Bitrix\Main\ORM\Objectify\Values::ACTUAL - вернутся только исходные значения полей
\Bitrix\Main\ORM\Objectify\Values::CURRENT - вернутся только текущие значения полей
\Bitrix\Main\ORM\Objectify\Values::ALL - вернутся все значения полей.
public function getCompatibleData
(int $valuesType = Values::ALL): array

$valuesType принимает те же значения и с тем же смыслом, что и в методе getData
Вернет массив значений полей элемента в том же формате, в котором работа с ними производилась в "старом" API.
Здесь коды полей отдаются в кодах, специфических для конкретного типа.
Значения полей преобразуются в строки / числа / массивы.
public function getCompatibleData
(int $valuesType = Values::ALL): array

$valuesType принимает те же значения и с тем же смыслом, что и в методе getData
Вернет массив значений полей элемента в том же формате, в котором работа с ними производилась в "старом" API.
Здесь коды полей отдаются в кодах, специфических для конкретного типа.
Значения полей преобразуются в строки / числа / массивы.
public function setFromCompatibleData(array $data): self
Метод запишет новые значения полей из массива $data. Данные в массиве должны быть в формате "старого" API.
Ключами массива должны являться коды полей, специфических для конкретного типа.
Если элемент является новым, и значение какого-то поля не передано, то в элемент будет записано значение этого поля по умолчанию (см. метод getDefaultValue).
public function isNew(): bool
Вернет true, если элемент ещё не сохранен в базу данных.
public function getId(): int
Вернет идентификатор элемента.
public function getEntityTypeId(): int
Вернет идентификатор типа сущности CRM.
public function getTitlePlaceholder(): ?string
Вернет заголовок по умолчанию, предназначенный для показа в форме создания.
public function save(bool $isCheckUserFields = true): Result
Сохранит текущее состояние элемента в базу данных. Вернет объект Bitrix\Main\Result.
Флаг $isCheckUserFields говорит о том, надо ли проверять корректность заполнения пользовательских полей при сохранении.
Этот метод выполняет только сохранение в базу данных. Внутри него не выполняются никакие дополнительные действия (кроме обработчиков событий, подписанных на таблет).
Все дополнительные действия производятся через операции.
public function delete(): Result
Удаляет элемент из базы данных, возвращает Bitrix\Main\Result.
Флаг $isCheckUserFields говорит о том, надо ли проверять корректность заполнения пользовательских полей при сохранении.
Метод выполняет только непосредственно удаление.
Для учета всех дополнительных действий надо воспользоваться операцией.
public function jsonSerialize(): array
Вернет данные об элементе в подготовленном для фронта или REST виде (см. Service\Converter).
public function getEntityFieldNameIfExists
(string $commonFieldName): ?string
Вернет специфический для типа код поля по его "общему" названию.
public function isCategoriesSupported(): bool
Вернет true, если тип элемента поддерживает работу с направлениями.
public function isStagesEnabled(): bool
Вернет true, если для типа элемента должны отображаться стадии в интерфейсе.
public function getCategoryIdForPermissions(): int
Вернет идентификатор направления для учета при проверке прав доступа. Если направления не поддерживаются, возвращает 0.

Работа с коллекциями

Все методы, изменяющие состояние привязанных коллекций, не производят запись изменений в базу данных. Они только изменяют состояние объекта (аналогично поведению методов get/ set).

Чтобы приведенные ниже методы работали корректно, из БД должны быть выбраны соответствующие данные: поля Item::FIELD_NAME_CONTACTS или Item::FIELD_NAME_CONTACT_BINDINGS для работы с контактами, поле Item::FIELD_NAME_OBSERVERS и поле Item::FIELD_NAME_PRODUCTS для товарных позиций.

Сделать это можно, передав в select метода Factory::getItems необходимые поля.

Если же необходимо получить один элемент, то можно воспользоваться методом Factory::getItem. Он вернет объект, для которого из БД получены все связанные записи.

Чтобы изменения были сохранены, необходимо вызвать метод save.

Метод Описание С версии
public function getPrimaryContact(): ?Contact
Вернет orm-объект с "основным" контактом, если есть хотя бы один.
public function getContacts(): array
Вернет массив orm-объектов привязанных контактов.
public function bindContacts(array $contactBindings): void
Запишет связь с контактами $contactBindings элемента.
Данные $contactBindings должны быть в формате, который отдает метод \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
public function unbindContacts(array $contactBindings): void
Удалит связь с контактами $contactBindings элемента.
Данные $contactBindings должны быть в формате, который отдает метод \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
public function getContactBindings(): array
Вернет данные о текущих привязках контактов.
Результат будет в формате, который отдает метод \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
public function getObservers(): array
Вернет массив идентификаторов пользователей, которые являются наблюдателями у элемента.
public function setObservers($observerIds): Item
Запишет идентификаторы пользователей $observerIds в данные о наблюдателях.
Все необходимые действия по сохранению атрибутов доступа и созданию чатов будут произведены при выполнении операции в классе Bitrix\Crm\Field\Observers.
public function addToProductRows(ProductRow $product): Result
Метод добавит orm-объект товарной позиции $product к текущей коллекции товарных позиций.
public function removeFromProductRows(ProductRow $product): void
Метод удалит orm-объект товарной позиции $product из текущей коллекции товарных позиций.
public function setProductRowsFromArrays(array $productArrays): Result
Метод перезапишет данные о коллекции товаров из массива $productArrays.
Каждый элемент массива $productArrays - это массив данных о товарной позиции.
public function setProductRows($products): Result
Метод перезапишет данные о коллекции товаров из параметра $products. $products может быть либо массивом orm-объектов ProductRow, либо коллекцией ProductRowCollection.

Пользовательские поля. Файловые поля

Для класса нет особенной разницы, с какими полями он работает - полями самой таблицы или пользовательскими. Главное, чтобы эти поля были доступны в EntityObject.

Есть некоторые особенности при обработке полей типа "Файл".

Особенности работы с файловыми полями

С точки зрения базы данных тип поля "Файл" - это число. Но в старом API файл перед сохранением можно было передать в виде массива с описанием загруженного файла (см. \CFile::MakeFileArray())

Чтобы этот способ работал, при передаче таких данных в метод setFromCompatibleData файл сразу сохраняется в таблицу b_file, а его ID записывается в поле EntityObject.

Загрузка производится через сервис загрузки файлов, который очистит файлы, которые не были сохранены.

Примеры


Создание элемента


use Bitrix\Crm\Service;
use Bitrix\Crm\Item;

$factory = Service\Container::getInstance()->getFactory(\CCrmOwnerType::Quote);

$newFile = [
    'name' => 'document.docx',
    'size' => 145961,
    'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'description' => '', 
    'tmp_name' => '/tmp/d1gadg',
];

$fields = [
    'UF_CRM_FIELD' => 'some value',
    'UF_CRM_FILE' => $newFile,
];
$item = $factory->createItem([
    Item::FIELD_NAME_STAGE_ID => 'D128_3:CLIENT' ,
]);
$item->setFromCompatibleData($fields);

// here we can get new file identifier. But if item not saved, this file will be deleted.
$newFileId = $item->get('UF_CRM_FILE');

$result = $item->save();

Изменение элемента


use Bitrix\Crm\Service;
use Bitrix\Crm\Item;

$factory = Service\Container::getInstance()->getFactory(\CCrmOwnerType::Quote);

$item = $factory->getItem(1);
if ($item)
{
    $item->setStageId('SENT');
    $result = $item->save();
}

Удаление элемента


use Bitrix\Crm\Service;
use Bitrix\Crm\Item;

$factory = Service\Container::getInstance()->getFactory(\CCrmOwnerType::Quote);

$item = $factory->getItem(1);
if ($item)
{
    $result = $item->delete();
}

Изменение контактов


Представим, что у нас есть коммерческое предложение с id = 1, привязанное к двум контактам с id = 2 и id = 3. Мы хотим, чтобы оно было привязано к контактам 3 и 4.


use Bitrix\Crm\Binding\EntityBinding;
use Bitrix\Crm\Item;
use Bitrix\Crm\Service;


$factory = Service\Container::getInstance()->getFactory(\CCrmOwnerType::Quote);

$item = $factory->getItem(1);
if ($item)
{
    // add new contact with id = 4
    $item->bindContacts(EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, [4]));
    // remove contact with id = 2
    $item->unbindContacts(EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, [2]));
}

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


Работа с этим классом имеет ряд преимуществ:

  • Легко определить, было ли изменено значение поля (через метод isChanged).
  • Прозрачный доступ к значениям полей, соответственно их смыслу, независимо от их кода в таблице.
  • Типизация и autocomplete.
  • Возможность работать с абстракцией.

При работе с этим классом есть ряд недостатков, связанных с особенностями поведения EntityObject:

  • Значения полей приводятся к соответствующему типу. Из-за этого числовые поля с незаполненными значениями отдают 0. И нет никакой возможности определить, там записан 0 или поле не заполнено.
  • При работе непосредственно с объектом нет возможности определить, было ли значение поля передано с фронта, или нет. Метод isChanged говорит только о том, изменено ли значение.

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

Пользовательские комментарии

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

Для этого нужно всего лишь авторизоваться на сайте

Но помните, что Пользовательские комментарии, несмотря на модерацию, не являются официальной документацией. Ответственность за их использование несет сам пользователь.

Также Пользовательские комментарии не являются местом для обсуждения функционала. По подобным вопросам обращайтесь на форумы.
© «Битрикс», 2001-2021, «1С-Битрикс», 2021
Наверх