Заготовка для работы с REST-API Битрикс24 на PHP
В марте 2021 года возникла необходимость различных доработок функциональности а также интеграций, для нашей облачной CRM-системы Битрикс24. Удобных комплектов кода не было найдено, разве что кое-какие куски или то, что приходилось перепиливать. Попадались сайты обучателей, которые за некоторую сумму предлагали обучить основам. Мой метод простой и бесплатный.
Было принято решение, написать немного своего кода на php, несколько классов, чтобы было удобно и просто выполнять запросы к REST-API Битрикс24. Ссылка на официальный сайт, с описанием методов https://dev.1c-bitrix.ru/rest_help/
Данное решение написано с вариантом использования “Входящий вебхук”, где запросы к API выполняются по схеме представленной ниже:
По сути – это URL запрос, который содержит токен, метод и параметры для запроса, можно ее хоть в браузер вставлять и получать результат. Где в данном случае, в запросе получается список сделок по фильтру: не закрытые и с ID больше 2200. В принципе, если нужно выполнить всего 1 или 2 простых запроса и они не будут меняться, можно использовать CURL – запросы и не усложнять себе жизнь. Если же в планах есть построение сложных интеграций, с выборкой большого количества данных, то можно использовать то, что будет описано ниже. В конце статьи можно будет скачать исходники.
Как получить токен(ссылку) для выполнения запросов к API, процесс представлен на картинках ниже, в связи с периодическим обновлением интерфейса, он может со временем отличаться.
Шаг 1 – находим пункт “Разработчикам” в меню или строке поиска, переходим
Шаг 2 – в следующей вкладке выбираем “Другое”
Шаг 3 – в следующей вкладке выбираем “Входящий вебхук”
Шаг 4 – в следующей вкладке получаем ссылку-токен, настраиваем разрешения(права) нажимаем сохранить
Что стоит знать, прежде чем писать интеграции с Битрикс24:
- За один запрос к API – Битрикс24 выдает не более 50 результатов и ссылку на следующие 50;
- Есть ограничение по количеству запросов к API в секунду.
В примерах к этой статье разберем как быть, чтобы не испытывать сложностей из-за этих ограничений.
Первоначальная структура проекта:
- Файл composer.json
- Файл index.php
- Директория src
- –Файл B24.php
Содержимое каждого файла рассмотрим подробно. Забегая вперед, сообщу, что в данной статье не будет рассмотрен сложный роутинг, сейчас главное понять концепцию и начать ее использовать. Запросы к API будут выполняться при помощи GUZZLE, чтобы не писать большие куски кода, в случае c CURL.
Файл composer.json – Будет содержать подключение пакета GUZZLE и инструкции для подключения файлов наших классов из директории src. Его код:
{
"require": {
"guzzlehttp/guzzle": "^6.0"
},
"autoload": {
"psr-4": { "": "src/" }
}
}
Выполняем команду в терминале, в этой директории: composer require
Получаем примерно такой результат:
Search for a package: ./composer.json has been updated Running composer update Loading composer repositories with package information Updating dependencies Lock file operations: 8 installs, 0 updates, 0 removals - Locking guzzlehttp/guzzle (6.5.5) - Locking guzzlehttp/promises (1.5.1) - Locking guzzlehttp/psr7 (1.8.5) - Locking psr/http-message (1.0.1) - Locking ralouphie/getallheaders (3.0.3) - Locking symfony/polyfill-intl-idn (v1.25.0) - Locking symfony/polyfill-intl-normalizer (v1.25.0) - Locking symfony/polyfill-php72 (v1.25.0) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 8 installs, 0 updates, 0 removals - Installing symfony/polyfill-php72 (v1.25.0): Extracting archive - Installing symfony/polyfill-intl-normalizer (v1.25.0): Extracting archive - Installing symfony/polyfill-intl-idn (v1.25.0): Extracting archive - Installing ralouphie/getallheaders (3.0.3): Extracting archive - Installing psr/http-message (1.0.1): Extracting archive - Installing guzzlehttp/psr7 (1.8.5): Extracting archive - Installing guzzlehttp/promises (1.5.1): Extracting archive - Installing guzzlehttp/guzzle (6.5.5): Extracting archive 4 package suggestions were added by new dependencies, use `composer suggest` to see details. Generating autoload files 5 packages you are using are looking for funding. Use the `composer fund` command to find out more!
Необходимые пакеты и зависимости загрузились, а также создались дополнительные файлы(composer.lock) и директория(vendor), куда все это загрузилось. Если на данном этапе у Вас этого не произошло, то нужно проверить установлен ли composer, это можно сделать командой: composer -v
Файл index.php – на данном этапе точка входа в приложение. Пока у нас нет класса B24, то описывать его не имеет смысла, вернемся к этому чуть позже. Сейчас его можно просто создать, с открывающим тегом
Файл B24.php – Это будет основной класс, где будут описаны методы для работы с REST-API. В этом классе основных два метода, oneMethod и listMethod, первый для выполнения простых запросов, например записать что-то в лид или сделку, отправить сообщение в чат, получить конкретную сделку и тд, а второй чтобы получать массивы больших данных, например сделки по фильтру, все сделки, лиды, элементы списка и тд. Код файла:
<?php
use GuzzleHttp\Client;
/**
*
* Простой класс для работы с REST-API Битрикс24
*
*/
class B24 extends Client
{
protected $conftoken = null;
public $arrToallDealList = array();
protected $reqMethod = '';
protected $reqParam = array();
/**
* Установка URL-адреса токена во время инициализации объекта,
* для последующего использования, также вызываем родительский конструктор
*/
function __construct($token) {
parent::__construct();
$this->conftoken = $token;
}
/**
*
* Выполнение простого метода, не списочного
* @param array $params Параметры для запроса
* @param string $method Название метода
* @return array Ассоциативный массив
* Пример использования : $obj->oneMethod(array('ID'=>245),'crm.lead.get');
*
*/
public function oneMethod(array $params, string $method): mixed
{
$init = $this->conftoken;
if($init) {
$response = $this->request('POST', '$this->conftoken/$method.json',['json'=>$params],['http_errors' => false]);
return json_decode($response->getBody(),true);
}else{
return false;
}
}
/**
*
* Заполнение массива для метода listMethod()
* если результат запроса составляет более 50 элементов.
* Вызывается методом listMethod()
* $arrtoalldeallist свойство заполняется в цикле.
* Происходит проверка на наличие ключа 'next' в $arrResult
* Если такой ключ есть, то вызывается метод listMethod.
* Ему передаются параметры, которые хранятся в свойствах $reqmethod и $reqparam
* В противном случае возвращается свойство arrToallDealList
* Между запросами существует интервал в 1 секунду
* @param array $arrResult Результат метода listMethod()
* @return array Ассоциативный массив
*
*/
public function arrCombine(array $arrResult): array
{
foreach($arrResult['result'] as $key => $value) {
$this->arrToallDealList[] = $value;
}
if(array_key_exists('next', $arrResult)) {
sleep(1);
$this->listMethod($this->reqParam,$this->reqMethod);
}
return $this->arrToallDealList;
}
/**
*
* Для выполнения запросов к списочным методам.
* Полученный результат отправляется в метод arrCombine()
* Как параметр
* Метод вернет все результаты в одном массиве
* Сохраняет параметры запроса в свойстве $reqParam
* Сохраняет имя метода в свойстве $reqMethod
* @param array $params Параметры для запроса
* @param string $method Метод для запроса
* @return bool|array Ассоциативный массив с всеми результатами
* Пример использования: $obj->listMethod(array('SELECT' => array('ID', 'TITLE'),'FILTER' => array('>OPPORTUNITY' => '50000')),'crm.deal.list');
*
*/
public function listMethod(array $params,string $method): bool|array
{
$init = $this->conftoken;
if($init) {
$response = $this->request('POST', '$this->conftoken/$method.json',['json'=>$params],['http_errors' => false]);
$result = json_decode($response->getBody(),true);
if(array_key_exists('next', $result)) {
$params['start'] = $result['next'];
$this->reqParam = $params;
$this->reqMethod = $method;
}
return $this->arrCombine($result);
}else {
return false;
}
}
}
!!! ВАЖНО !!! Данный код написан на PHP 8, для использования его на более ранних версиях, необходимо убрать у методов описание возвращаемых результатов “: bool|array”
После создания этого файла, запускаем команду в консоле, в корне проекта composer dump-autoload -o.
После выполнения этой команды, увидим примерно такой результат:
Generating optimized autoload files Generated optimized autoload files containing 96 classes
Я оставил комментарии в коде класса, в том числе примеры использования вызовов методом, но все же внесу несколько объяснений. При создание объекта от класса B24, в конструктор необходимо передать ссылку, с токеном, которую мы получим в системе Битрикс24, переданное значение сохраняется в свойстве conftoken, затем проверяется в каждом методе. С методом oneMethod – все просто, происходит выполнение обычного запроса, не предполагающего получение результата более 50 элементов. Сложнее становится с методом listMethod, в нем также сначала выполняется простой запрос, а затем проверяется ответ, на содержание в нем ключа ‘next’, что будет означать, что есть еще данные. Для того чтобы формировать новые запросы, нужно сохранить куда-то данные из выполненного запроса, поэтому они сохраняются в свойства объекта $reqMethod и $reqParam, а также к ним добавляется значение start, которое копируется из получаемого значения next, затем управление передается служебному методу arrCombine, который наполняет свойство объекта arrToallDealList, затем опять передает управление методу listMethod и так по кругу, пока не произойдет выборка всех элементов, можно сказать, что это работает как рекурсивная функция, в конечном итоге мы получим многомерный массив, даже если там несколько тысяч элементов, а уже с ним можно делать все что угодно. Для стартовой работы из php – этого достаточно, конечно Вы можете дополнить этот класс, при необходимости.
Примеры использования
Пример 1 – выполнение простого запроса, получить сделку по ID:
Теперь самое время изменить написать содержимое файла index.php, его код, согласно примеру:
<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';
// создаем объект от класса B24, в конструктор передаем ссылку-токен
// в Вашем случае будет другая ссылка с токеном
$obj = new B24('https://my_domain.bitrix24.ru/rest/3/jsudurewurewfs/');
// в переменную $result сохраняем результат выполнения обычного метода
$result = $obj->oneMethod(array('ID'=> 4043),'crm.deal.get');
// распечатываем результат
echo '<pre>';
print_r($result);
echo '</pre>';
Получаем примерно такой результат:
Array
(
[result] => Array
(
[ID] => 4043
[TITLE] => Переборка щита, монтаж розеток
[TYPE_ID] => SALE
[STAGE_ID] => C5:PREPAYMENT_INVOICE
[PROBABILITY] =>
[CURRENCY_ID] => RUB
[OPPORTUNITY] => 28330.00
[IS_MANUAL_OPPORTUNITY] => N
[TAX_VALUE] => 0.00
[LEAD_ID] => 16359
[COMPANY_ID] => 0
[CONTACT_ID] => 5219
[QUOTE_ID] =>
[BEGINDATE] => 2022-04-22T03:00:00+03:00
[CLOSEDATE] => 2022-04-29T03:00:00+03:00
[ASSIGNED_BY_ID] => 191
[CREATED_BY_ID] => 191
[MODIFY_BY_ID] => 0
[DATE_CREATE] => 2022-04-22T08:11:59+03:00
[DATE_MODIFY] => 2022-04-22T16:03:53+03:00
[OPENED] => Y
.......................................
[UF_CRM_1615032085] => Array
(
[0] => 14000|RUB
)
[UF_CRM_1615032130] => 14330|RUB
[UF_CRM_1627388924] => Array
[UF_CRM_600AA3417AD7A] =>
[UF_CRM_600AA34196346] => электромонтажные работы
[UF_CRM_1600853246] => Array
(
[0] => 3489
)
[UF_CRM_1611312294] => 4043
[UF_CRM_1598962957887] =>
[UF_CRM_1612422559] =>
[UF_CRM_60B7612B258FE] =>
[UF_CRM_6091407D6FEB3] => 2022-04-21T03:00:00+03:00
[UF_CRM_1618408288] => 0
[UF_CRM_1618408480] => 0
[UF_CRM_1598957086824] =>
[UF_CRM_1598958542281] => 25580|RUB
[UF_CRM_1598959848727] => Array
(
[0] => Новинский бульвар, 1 строение 1, Москва, Россия|55.54070539999999;35.5835639
)
[UF_CRM_1598959911645] =>
[UF_CRM_1598960178922] => 2022-04-22T03:00:00+03:00
[UF_CRM_1598960208246] =>
[UF_CRM_DCT_DURATION] =>
[UF_CRM_DCT_PAGE] =>
[UF_CRM_DCT_CONTEXT] =>
[UF_CRM_CONTACT_IDS] => Array
(
)
[UF_CRM_LEAD_ID] => 0
[UF_CRM_CODE] =>
[UF_CRM_CATEGORY_ID] =>
[UF_CRM_1460372641] =>
[UF_CRM_1481007906] =>
[UF_CRM_CLOSED] => 0
[UF_CRM_1478673224] =>
[UF_CRM_DETAIL_PAGE_URL] =>
[UF_CRM_STAGE_ID] =>
[UF_CRM_OPPORTUNITY_ACCOUNT] =>
[UF_CRM_TYPE_ID] =>
[UF_CRM_UF_PREVIEW_TEXT_TYPE] =>
(
)
[UF_CRM_1623333428] => 0
)
[time] => Array
(
[start] => 1650891456.3004
[finish] => 1650891456.6565
[duration] => 0.35612511634827
[processing] => 0.29077291488647
[date_start] => 2022-04-25T15:57:36+03:00
[date_finish] => 2022-04-25T15:57:36+03:00
[operating] => 20.724123954773
)
)
В итоге мы получили ассоциативный массив, со всеми данными по конкретной сделке.
Чтобы получить все сделки по фильтру, используем списочный метод, пример кода:
<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';
// создаем объект от класса B24, в конструктор передаем ссылку-токен
// в Вашем случае будет другая ссылка с токеном
$obj = new B24('https://my_domain.bitrix24.ru/rest/3/jsudurewurewfs/');
// формируем массив с параметрами для запроса
$arrToReq = array(
'FILTER' => array(
'CLOSED' => 'N',
'>ID' => 2000,
),
'SELECT' => array(
'ID', 'STAGE_ID', 'PROBABILITY', 'OPPORTUNITY', 'CURRENCY_ID'
),
);
// в переменную $result сохраняем результат выполнения списочного метода
$result = $obj->listMethod($arrToReq,'crm.deal.list');
// распечатываем результат
echo '<pre>';
print_r($result);
echo '</pre>';
В коде выше, был вызван списочный метод, для получения всех сделок, которые не закрыты и их ID больше 2000, а также выбраны определенные поля.
Результат в моем случае, я его чуть сократил, но в итоге было получено 490 элементов по фильтру
Array
(
[0] => Array
(
[ID] => 2005
[STAGE_ID] => C5:FINAL_INVOICE
[PROBABILITY] =>
[OPPORTUNITY] => 45000.00
[CURRENCY_ID] => RUB
)
[1] => Array
(
[ID] => 2017
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 4800.00
[CURRENCY_ID] => RUB
)
[2] => Array
(
[ID] => 2041
[STAGE_ID] => C3:3
[PROBABILITY] =>
[OPPORTUNITY] => 9000.00
[CURRENCY_ID] => RUB
)
[3] => Array
(
[ID] => 2043
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 30010.00
[CURRENCY_ID] => RUB
)
[4] => Array
(
[ID] => 2045
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 80000.00
[CURRENCY_ID] => RUB
)
[5] => Array
(
[ID] => 2053
[STAGE_ID] => C5:2
[PROBABILITY] =>
[OPPORTUNITY] => 11429.10
[CURRENCY_ID] => RUB
)
[6] => Array
(
[ID] => 2057
[STAGE_ID] => C5:EXECUTING
[PROBABILITY] =>
[OPPORTUNITY] => 151885.80
[CURRENCY_ID] => RUB
)
[7] => Array
(
[ID] => 2065
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 20000.00
[CURRENCY_ID] => RUB
)
[8] => Array
(
[ID] => 2071
[STAGE_ID] => C3:6
[PROBABILITY] =>
[OPPORTUNITY] => 0.00
[CURRENCY_ID] => RUB
)
[9] => Array
(
[ID] => 2087
[STAGE_ID] => C5:2
[PROBABILITY] =>
[OPPORTUNITY] => 9505.25
[CURRENCY_ID] => RUB
)
[10] => Array
(
[ID] => 2089
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 17000.00
[CURRENCY_ID] => RUB
)
[11] => Array
(
[ID] => 2093
[STAGE_ID] => C3:10
[PROBABILITY] =>
[OPPORTUNITY] => 40610.00
[CURRENCY_ID] => RUB
)
...................... вырезано от 12 до 120 ................
[121] => Array
(
[ID] => 2723
[STAGE_ID] => C9:3
[PROBABILITY] =>
[OPPORTUNITY] =>
[CURRENCY_ID] => RUB
)
[122] => Array
(
[ID] => 2725
[STAGE_ID] => C9:3
[PROBABILITY] =>
[OPPORTUNITY] =>
[CURRENCY_ID] => RUB
)
...................... вырезано от 123 до 487 ................
[488] => Array
(
[ID] => 4059
[STAGE_ID] => C5:NEW
[PROBABILITY] =>
[OPPORTUNITY] => 69350.00
[CURRENCY_ID] => RUB
)
[489] => Array
(
[ID] => 4061
[STAGE_ID] => C3:1
[PROBABILITY] =>
[OPPORTUNITY] => 0.00
[CURRENCY_ID] => RUB
)
[490] => Array
(
[ID] => 4063
[STAGE_ID] => C3:1
[PROBABILITY] =>
[OPPORTUNITY] => 30600.00
[CURRENCY_ID] => RUB
)
)
Списочный метод, для получения результатов более 50, работает, но имеет интересный эффект, если он будет вызван несколько раз, то в итоге мы получим общий массив, включающий в себя и предыдущие результаты, что не всегда нужно, тут два варианта действий: создать новый объект и вызвать у него списочный метод или добавить еще один метод и вызывать его, при повторном вызове списочного метода, для очистки свойства arrToallDealList. Добавим в файл B24.php, фрагмент кода:
/**
* Метод очистки свойства $arrToallDealList,
* Необходимо вызывать, если у создаваемого объекта
* списочный метод вызывается несколько раз.
*/
public function cleanArr()
{
unset($this->arrToallDealList);
}
Всем успехов в разработке и интеграциях.
По ссылкам ниже можно скачать файлы. Для разворачивания, необходимо будет запустить команду composer require и потом команду composer dump-autoload -o
Скачать исходники
Рекламный блок, для развития проекта
Данная статья будет отправной точкой, по всем остальным доработкам и интеграциям, описанным на этом сайте.
Тестируйте, пишите свои комментарии, вопросы и замечания, обязательно рассмотрим.