Заготовка для работы с REST-API Битрикс24 на PHP

В марте 2021 года возникла необходимость различных доработок функциональности а также интеграций, для нашей облачной CRM-системы Битрикс24. Удобных комплектов кода не было найдено, разве что кое-какие куски или то, что приходилось перепиливать. Попадались сайты обучателей, которые за некоторую сумму предлагали обучить основам. Мой метод простой и бесплатный.

Было принято решение, написать немного своего кода на php, несколько классов, чтобы было удобно и просто выполнять запросы к REST-API Битрикс24. Ссылка на официальный сайт, с описанием методов https://dev.1c-bitrix.ru/rest_help/

Данное решение написано с вариантом использования «Входящий вебхук», где запросы к API выполняются по схеме представленной ниже:


запросы к REST-API битрикс24

По сути — это URL запрос, который содержит токен, метод и параметры для запроса, можно ее хоть в браузер вставлять и получать результат. Где в данном случае, в запросе получается список сделок по фильтру: не закрытые и с ID больше 2200. В принципе, если нужно выполнить всего 1 или 2 простых запроса и они не будут меняться, можно использовать CURL — запросы и не усложнять себе жизнь. Если же в планах есть построение сложных интеграций, с выборкой большого количества данных, то можно использовать то, что будет описано ниже. В конце статьи можно будет скачать исходники.

Как получить токен(ссылку) для выполнения запросов к API, процесс представлен на картинках ниже, в связи с периодическим обновлением интерфейса, он может со временем отличаться.

Шаг 1 — находим пункт «Разработчикам» в меню или строке поиска, переходим


шаг 1 получение токена

Шаг 2 — в следующей вкладке выбираем «Другое»


шаг 2 получения токена ссылки

Шаг 3 — в следующей вкладке выбираем «Входящий вебхук»


шаг 3 получения токена

Шаг 4 — в следующей вкладке получаем ссылку-токен, настраиваем разрешения(права) нажимаем сохранить


шаг 4 получения токена битрикс24

Что стоит знать, прежде чем писать интеграции с Битрикс24:

  1. За один запрос к API — Битрикс24 выдает не более 50 результатов и ссылку на следующие 50;
  2. Есть ограничение по количеству запросов к 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


Скачать исходники

Рекламный блок, для развития проекта




Данная статья будет отправной точкой, по всем остальным доработкам и интеграциям, описанным на этом сайте.

Тестируйте, пишите свои комментарии, вопросы и замечания, обязательно рассмотрим.

Добавить комментарий

Ваш адрес email не будет опубликован.