Заготовка для работы с 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
Скачать исходники
Рекламный блок, для развития проекта
Данная статья будет отправной точкой, по всем остальным доработкам и интеграциям, описанным на этом сайте.
Тестируйте, пишите свои комментарии, вопросы и замечания, обязательно рассмотрим.