Начало работы
Введение
Исторически так сложилось, что манипуляция данными об элементах основных сущностей 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 = [])
|
Использовать конструктор напрямую настоятельно не рекомендуется. Для получения объектов необходимо использовать соответствующие методы фабрики. | |
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
говорит только о том, изменено ли значение.
Эти недостатки известны, возможно, через некоторое время будут добавлены новые методы, позволяющие их нивелировать.
Сообщение не промодерировано, возможны ошибки и неточности.
|
||
Добавить в созданную сущность телефон или email:
| ||
Сообщение не промодерировано, возможны ошибки и неточности.
|
||
Пример создания элемента смарт-процесса с добавлением товарных позиций:
| ||
Пользовательские комментарии
Мы будем рады, если разработчики добавят свои комментарии по практическому использованию методов системы.Для этого нужно всего лишь авторизоваться на сайте
Но помните, что Пользовательские комментарии, несмотря на модерацию, не являются официальной документацией. Ответственность за их использование несет сам пользователь.
Также Пользовательские комментарии не являются местом для обсуждения функционала. По подобным вопросам обращайтесь на форумы.