Start
Introduction
In general, element data for main CRM entities is performed using an array.
This approach has several drawbacks:
- Various entities have different field names, but the same content. Their names must always be memorized.
- No autocomplete in IDE.
- No type checking and etc.
To unify the approach and resolve all the above listed deficiencies new API has introduced an abstract class Bitrix\Crm\Item
.
This class contains Bitrix\Main\ORM\Objectify\EntityObject
and imitates its behaviour.
Each entity type has its own implementation of this class containing specifics of this type.
Class reproduces the interface \ArrayAccess
, when querying the object as an array, calling methods get
and set
.
Codes for "general" fields of this class are based on the corresponding field codes for SPA element table.
Because the class itself doesn't query the database directly, its fully dependant on the status of internal EntityObject
.
Meaning, when object have some empty data (not passed in select
), the class won't have access to such data.
Names methods
Class has a set of names methods (similar to EntityObject
) for handling status and value of fields.
For example, method getStageId
returns string ID for element stage. Even if the field is named not as STAGE_ID, but STATUS_ID, method will still operate.
In similar fashion, method setStageId
writes new value into the stage field, independently from its code in element table.
The method isChangedStageId
operates in the same manner. The rest of cases, available in EntityObject
are not implemented.
Handling of named methods is implemented via the "magic" method __call
.
Below is full set of methods, available for handling "Title" field (TITLE):
getTitle(): ?string
- returns current value;setTItle(string $title): Item
- write new value;isChangedTitle(): bool
- returns true, when field value was updated.
In similar fashion you can query methods for other fields. Field code must be converted into UpperCamelCase notation.
Example:
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
Similarly, you can handle UTM-tag fields. Although, values for these fields are not stored directly in table with elements, they can be accessed in the same manner from this class.
getUtmSource(): ?string
getUtmMedium(): ?string
getUtmCampaign(): ?string
getUtmContent(): ?string
getUtmTerm(): ?string
General methods
Method | Description | Available from version |
---|---|---|
public function __construct(int $entityTypeId, EntityObject $entityObject, array $fieldsMap = [], array $disabledFieldNames = [])
|
Its not recommended to use the constructor directly. Use the corresponding factory methods for getting objects. | |
public function hasField(string $fieldName): bool |
Returns true, when element has the field with $fieldName.
Here and later $fieldName can be both "general", and specific for entity.
For example, hasField('STAGE_ID') and hasField('STATUS_ID') for "Lead" entity element both return true.
| |
public function getDefaultValue(string $fieldName) |
Returns default value for the field $fieldName. | |
public function get(string $fieldName) |
Returns current field value for $fieldName. | |
public function set(string $fieldName, $value): self |
Writes new current $value for the field $fieldName. | |
public function reset(string $fieldName): self |
Resets $fieldName to initial status. | |
public function unset(string $fieldName): self |
Writes empty value to the field $fieldName. | |
public function remindActual(string $fieldName) |
Returns initial field value $fieldName. | |
public function isChanged(string $fieldName): bool |
Returns true, when field $fieldName was updated (current value is different from initial). | |
public function getData(int $valuesType = Values::ALL): array |
Returns array with field values, where keys are "general" field codes, and values - field values, selected by mask $valuesType.
$valuesType can receive values, described in the class \Bitrix\Main\ORM\Objectify\Values :
\Bitrix\Main\ORM\Objectify\Values::ACTUAL - returns only initial field values\Bitrix\Main\ORM\Objectify\Values::CURRENT - returns only current field values\Bitrix\Main\ORM\Objectify\Values::ALL - returns all field values. | |
public function getCompatibleData (int $valuesType = Values::ALL): array $valuesType accepts the same values with the same content as in the method getData
|
Returns array with field values in the same format as processed in the "legacy" API.
Here, field codes are passed in codes specific for individual type. Field values are converted to strings/numericals/arrays. | |
public function getCompatibleData (int $valuesType = Values::ALL): array $valuesType accepts the same values with the same content as in the method getData
|
Returns array with field values in the same format as processed in the "legacy" API.
Here, field codes are passed in codes specific for individual type. Field values are converted to strings/numericals/arrays. | |
public function setFromCompatibleData(array $data): self |
Method writes new field values from the $data array. Array data must have format of "legacy" API.
Array keys must be field codes, specific for the individual type. If the element is new and the value of a field is not passed, this field value is written into this element by default (see the method getDefaultValue ). | |
public function isNew(): bool |
Returns true when element is not yet saved in the database. | |
public function getId(): int |
Returns element ID. | |
public function getEntityTypeId(): int |
Returns CRM entity type ID. | |
public function getTitlePlaceholder(): ?string |
Returns default header to be displayed in the creation form. | |
public function save(bool $isCheckUserFields = true): Result |
Saves current element status in the database. Returns object Bitrix\Main\Result .
Flag $isCheckUserFields indicates a performed check for custom fields when saving.
This method executes only saving to the database. No additional actions are executed inside it (except of event handlers, subscribed to table).
All additional actions are performed via operations. | |
public function delete(): Result |
Deletes element from database, returns Bitrix\Main\Result .
Flag $isCheckUserFields indicates a performed check for custom fields when saving.
Method directly performs deletion.
All additional actions are performed via operations. | |
public function jsonSerialize(): array |
Returns element data in prepared format for the frontend or REST (see. Service\Converter). | |
public function getEntityFieldNameIfExists (string $commonFieldName): ?string |
Returns field code by its "general" name specific for the type. | |
public function isCategoriesSupported(): bool |
Returns true, when element type supports handling of pipelines. | |
public function isStagesEnabled(): bool |
Returns true, when element type must have stages displayed in the interface. | |
public function getCategoryIdForPermissions(): int |
Returns pipeline ID when verifying access permissions. When pipeline is not supported, returns 0. |
Handling collections
All methods that update status of associated collections doesn't write updates to the database. They only change object status (similar to the behaviour of methods get
/ set
).
For the belowlisted methods to operate correctly, corresponding data must be selected from the database: fields Item::FIELD_NAME_CONTACTS or Item::FIELD_NAME_CONTACT_BINDINGS for handling contacts, field Item::FIELD_NAME_OBSERVERS and field Item::FIELD_NAME_PRODUCTS for product items.
You can achieve this by passing necessary fields to select of the method Factory::getItems
.
When a single retrieved element is required, use the method Factory::getItem
. Returns the object for which all associated entries are received from the database.
To save all updates, call the method save
.
Method | Description | Available from version |
---|---|---|
public function getPrimaryContact(): ?Contact |
Returns ORM object with "main" contact, if at least one is available. | |
public function getContacts(): array |
Returns array with ORM objects of associated contacts. | |
public function bindContacts(array $contactBindings): void |
Writes a binding with contacts $contactBindings of element.
$contactBindings data must have format that passed by the method \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
| |
public function unbindContacts(array $contactBindings): void |
Deletes binding with element contacts $contactBindings.
$contactBindings data must have format, passed by the method \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
| |
public function getContactBindings(): array |
Returns data on current binding contacts.
Result will have format, passed by the method \Bitrix\Crm\Binding\EntityBinding::prepareEntityBindings().
| |
public function getObservers(): array |
Returns array with user IDs that are observers for an element. | |
public function setObservers($observerIds): Item |
Writes user $observerIds into the observer data.
All the required actions for saving access attributes and chat creating will be performed during operation in class Bitrix\Crm\Field\Observers . | |
public function addToProductRows(ProductRow $product): Result |
Method adds ORM object for $product position to current collection of product positions. | |
public function removeFromProductRows(ProductRow $product): void |
Method deletes ORM object for $product position from current collection of product positions. | |
public function setProductRowsFromArrays(array $productArrays): Result |
Method re-writes product collection data from the array $productArrays.
Each element from array $productArrays - is a data array for product position. | |
public function setProductRows($products): Result |
Method re-writes product collection data from $products parameter. $products can be an array of ProductRow ORM objects, or a ProductRowCollection . |
Custom fields, File fields.
Class doesn't differentiate which fields are handled: table fields or users. Only condition for these fields is to be available in EntityObject
.
There are some specifics when handling "File" type fields.
File fields handling particulars
From the database standpoint, "File" field type is just a number. However, in the legacy API, file must have been passed as an array with the uploaded file description (see. \CFile::MakeFileArray()
)
For this to work, passing such data to the method setFromCompatibleData
immediately saved to the table b_file, and its ID is written to the field EntityObject
.
Uploading is performed via the file loading service, clearing files that weren't saved.
Example
Creating an element
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();
Updating an element
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(); }
Deleting an element
use Bitrix\Crm\Service; use Bitrix\Crm\Item; $factory = Service\Container::getInstance()->getFactory(\CCrmOwnerType::Quote); $item = $factory->getItem(1); if ($item) { $result = $item->delete(); }
Updating contacts
For example, you have a commercial quote with id = 1, associated with two contacts with id = 2 and id = 3. We want for it to be bound to contacts 3 and 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])); }
Advantages and disadvantages
Working with this class has several advantages:
- Easy to determine if field value was updated (using the method
isChanged
). - Transparent access to field values, corresponding to their meaning, independent from their code in table.
- Type checking and autocomplete.
- Option to handle abstracts.
There are some disadvantages when handling this class, associated with behaviour specifics of EntityObject
:
- Field values are converted to corresponding type. Due to this, number fields with unfilled values pass 0. There is no option to define if this field has 0 or field is not filled.
- When directly handling the object there is no option to determine if field value was passed from the frontend or not. Method
isChanged
speaks only if the value was updated.
These deficiencies are known and pending to be resolved with newly added methods.