← Назад к справке

CRM

Контакты

Работа с контактами CRM через PHP и фабрики: получение, добавление, изменение, удаление, связь с компаниями и события.

Контакт — CRM-сущность для физического лица. Через фабрику удобно работать с основными полями контакта, а связь с компаниями хранится отдельно.

Основные операции

Базовая работа с контактами через фабрику CRM.

Получить контакт

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_CONTACT_TYPE_ID = \CCrmOwnerType::Contact;

Loader::includeModule('crm');

/**
 * Получает фабрику контактов.
 */
function fetchContactFactory()
{
    return Service\Container::getInstance()->getFactory(CRM_CONTACT_TYPE_ID);
}

/**
 * Получает контакт по ID.
 */
function fetchContactItem(int $contact_id)
{
    $factory = fetchContactFactory();

    if ($factory === null) {
        return null;
    }

    return $factory->getItem($contact_id);
}

$contact_item = fetchContactItem($contact_id);

if ($contact_item !== null) {
    $contact_data = $contact_item->toArray();
    $name = $contact_item->get('NAME');
    $last_name = $contact_item->get('LAST_NAME');

    print_r($contact_data);
}

Получить список контактов

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_CONTACT_TYPE_ID = \CCrmOwnerType::Contact;
const CONTACT_LIMIT = 100;

Loader::includeModule('crm');

/**
 * Получает фабрику контактов.
 */
function fetchContactFactory()
{
    return Service\Container::getInstance()->getFactory(CRM_CONTACT_TYPE_ID);
}

/**
 * Получает список контактов.
 */
function fetchContactItems(int $last_contact_id): array
{
    $factory = fetchContactFactory();

    if ($factory === null) {
        return [];
    }

    return $factory->getItems([
        'select' => [
            'ID',
            'NAME',
            'LAST_NAME',
            'SECOND_NAME',
            'COMPANY_ID',
            'ASSIGNED_BY_ID',
            'DATE_CREATE',
        ],
        'filter' => [
            '>ID' => $last_contact_id,
        ],
        'order' => [
            'ID' => 'ASC',
        ],
        'limit' => CONTACT_LIMIT,
    ]);
}

$contact_items = fetchContactItems(0);

foreach ($contact_items as $contact_item) {
    print_r($contact_item->toArray());
}

Добавить контакт

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_CONTACT_TYPE_ID = \CCrmOwnerType::Contact;

Loader::includeModule('crm');

/**
 * Получает фабрику контактов.
 */
function fetchContactFactory()
{
    return Service\Container::getInstance()->getFactory(CRM_CONTACT_TYPE_ID);
}

/**
 * Создаёт контакт.
 */
function addContact(string $name, string $last_name, int $assigned_by_id, int $company_id = 0): array
{
    $factory = fetchContactFactory();

    if ($factory === null) {
        return [
            'is_success' => false,
            'contact_id' => 0,
            'error_messages' => ['Фабрика контактов не найдена'],
        ];
    }

    $contact_item = $factory->createItem([
        'NAME' => $name,
        'LAST_NAME' => $last_name,
        'ASSIGNED_BY_ID' => $assigned_by_id,
        'COMPANY_ID' => $company_id,
    ]);

    $operation = $factory->getAddOperation($contact_item);
    $operation_result = $operation->launch();

    return [
        'is_success' => $operation_result->isSuccess(),
        'contact_id' => (int) $contact_item->getId(),
        'error_messages' => $operation_result->getErrorMessages(),
    ];
}

$add_result = addContact($name, $last_name, $assigned_by_id, $company_id);

print_r($add_result);

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

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_CONTACT_TYPE_ID = \CCrmOwnerType::Contact;

Loader::includeModule('crm');

/**
 * Получает фабрику контактов.
 */
function fetchContactFactory()
{
    return Service\Container::getInstance()->getFactory(CRM_CONTACT_TYPE_ID);
}

/**
 * Изменяет ФИО контакта.
 */
function updateContactName(int $contact_id, string $name, string $last_name): array
{
    $factory = fetchContactFactory();

    if ($factory === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Фабрика контактов не найдена'],
        ];
    }

    $contact_item = $factory->getItem($contact_id);

    if ($contact_item === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Контакт не найден'],
        ];
    }

    $contact_item->set('NAME', $name);
    $contact_item->set('LAST_NAME', $last_name);

    $operation = $factory->getUpdateOperation($contact_item);
    $operation_result = $operation->launch();

    return [
        'is_success' => $operation_result->isSuccess(),
        'error_messages' => $operation_result->getErrorMessages(),
    ];
}

$update_result = updateContactName($contact_id, $name, $last_name);

print_r($update_result);

Удалить контакт

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_CONTACT_TYPE_ID = \CCrmOwnerType::Contact;

Loader::includeModule('crm');

/**
 * Получает фабрику контактов.
 */
function fetchContactFactory()
{
    return Service\Container::getInstance()->getFactory(CRM_CONTACT_TYPE_ID);
}

/**
 * Удаляет контакт.
 */
function deleteContact(int $contact_id): array
{
    $factory = fetchContactFactory();

    if ($factory === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Фабрика контактов не найдена'],
        ];
    }

    $contact_item = $factory->getItem($contact_id);

    if ($contact_item === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Контакт не найден'],
        ];
    }

    $operation = $factory->getDeleteOperation($contact_item);
    $operation_result = $operation->launch();

    return [
        'is_success' => $operation_result->isSuccess(),
        'error_messages' => $operation_result->getErrorMessages(),
    ];
}

$delete_result = deleteContact($contact_id);

print_r($delete_result);

Связи

Контакт может быть связан с компанией.

Компании контакта

Поле COMPANY_ID удобно для одной связи с компанией. Если нужно работать со всеми связями контакта и компаний, лучше смотреть в сторону ContactCompanyTable.

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Binding\ContactCompanyTable;

Loader::includeModule('crm');

/**
 * Получает ID компаний контакта.
 */
function fetchContactCompanyIds(int $contact_id): array
{
    return ContactCompanyTable::getContactCompanyIDs($contact_id);
}

/**
 * Привязывает контакт к компаниям.
 */
function bindContactCompanies(int $contact_id, array $company_ids): void
{
    ContactCompanyTable::bindCompanyIDs($contact_id, $company_ids);
}

$company_ids = fetchContactCompanyIds($contact_id);

print_r($company_ids);

События

События контактов позволяют выполнить свой PHP-код перед добавлением, после добавления, перед изменением, после изменения, перед удалением и после удаления контакта.

Список событий

Обработчики обычно регистрируют в /local/php_interface/init.php или внутри своего модуля. Для коробочной разработки это удобный способ реагировать на изменения контактов без REST-приложения.

Событие Когда вызывается Метод
OnBeforeCrmContactAdd Перед добавлением контакта. CCrmContact::Add
OnAfterCrmContactAdd После добавления контакта. CCrmContact::Add
OnBeforeCrmContactUpdate Перед изменением контакта. CCrmContact::Update
OnAfterCrmContactUpdate После изменения контакта. CCrmContact::Update
OnBeforeCrmContactDelete Перед удалением контакта. CCrmContact::Delete
OnAfterCrmContactDelete После удаления контакта. CCrmContact::Delete
OnAfterExternalCrmContactAdd После добавления внешнего контакта. CCrmContact::Add

Перед добавлением

В OnBeforeCrmContactAdd можно изменить поля до сохранения или отменить создание контакта. Например, можно запретить создание полностью пустого контакта.

<?php

use Bitrix\Main\EventManager;

$event_manager = EventManager::getInstance();

/**
 * Регистрирует обработчик перед добавлением контакта.
 */
function registerBeforeContactAddHandler(EventManager $event_manager): void
{
    $event_manager->addEventHandlerCompatible(
        'crm',
        'OnBeforeCrmContactAdd',
        'handleBeforeContactAdd'
    );
}

/**
 * Обрабатывает поля перед добавлением контакта.
 */
function handleBeforeContactAdd(array &$contact_fields): bool
{
    global $APPLICATION;

    $name = trim((string) ($contact_fields['NAME'] ?? ''));
    $last_name = trim((string) ($contact_fields['LAST_NAME'] ?? ''));

    if ($name === '' && $last_name === '') {
        $APPLICATION->ThrowException('Не заполнены имя или фамилия контакта');

        return false;
    }

    if (empty($contact_fields['OPENED'])) {
        $contact_fields['OPENED'] = 'N';
    }

    return true;
}

registerBeforeContactAddHandler($event_manager);

В событиях до сохранения массив полей передаётся по ссылке. Если изменить значение в $contact_fields, оно попадёт в сохраняемый контакт.

После изменения

OnAfterCrmContactUpdate удобно использовать для логирования, синхронизации со своими таблицами или запуска вспомогательной логики после изменения контакта.

<?php

use Bitrix\Main\EventManager;

$event_manager = EventManager::getInstance();

/**
 * Регистрирует обработчик после изменения контакта.
 */
function registerAfterContactUpdateHandler(EventManager $event_manager): void
{
    $event_manager->addEventHandlerCompatible(
        'crm',
        'OnAfterCrmContactUpdate',
        'handleAfterContactUpdate'
    );
}

/**
 * Обрабатывает изменение контакта.
 */
function handleAfterContactUpdate(array &$contact_fields): void
{
    $contact_id = isset($contact_fields['ID']) ? (int) $contact_fields['ID'] : 0;

    if ($contact_id <= 0) {
        return;
    }

    AddMessage2Log(
        [
            'message' => 'Контакт изменён',
            'contact_id' => $contact_id,
            'fields' => $contact_fields,
        ],
        'contact_events'
    );
}

registerAfterContactUpdateHandler($event_manager);

Событие после изменения не всегда содержит полный набор полей контакта. Если нужно проверить поле, которого нет в $contact_fields, лучше отдельно получить контакт по ID.

Перед удалением

OnBeforeCrmContactDelete можно использовать, если удаление нужно проверить или запретить.

<?php

use Bitrix\Main\EventManager;

$event_manager = EventManager::getInstance();

/**
 * Регистрирует обработчик перед удалением контакта.
 */
function registerBeforeContactDeleteHandler(EventManager $event_manager): void
{
    $event_manager->addEventHandlerCompatible(
        'crm',
        'OnBeforeCrmContactDelete',
        'handleBeforeContactDelete'
    );
}

/**
 * Проверяет возможность удаления контакта.
 */
function handleBeforeContactDelete(int $contact_id): bool
{
    global $APPLICATION;

    $has_delete_access = true;

    if (!$has_delete_access) {
        $APPLICATION->ThrowException('Удаление контакта запрещено');

        return false;
    }

    AddMessage2Log(
        [
            'message' => 'Проверка перед удалением контакта',
            'contact_id' => $contact_id,
        ],
        'contact_events'
    );

    return true;
}

registerBeforeContactDeleteHandler($event_manager);

Источники