В начале сентября ветки 8.x-2.x и 7.x-2.x, разрабатываемого мною модуля CDEK API, добрались до полноценных релизов - все задуманные фичи реализованы и протестированы. В данной статье кратко расскажу о том, какие у модуля возможности и как их использовать.

Напомню, что модуль позволяет взаимодействовать с API сервиса доставки СДЭК и будет полезен исключительно для разработчиков, так как сам по себе он ничего не делает, не дополняет, не расширяет.

Главное отличие от веток 8.x-1.x и 7.x-1.x — это использование PHP библиотеки CDEK SDK для взаимодействия с API. Ставится библиотека с помощью Composer, для версии в Drupal 7 потребуется модуль Composer Manager.

Ветка 8.x-2.x потребует Drupal версии 8.8 или выше (Drupal 9 тоже поддерживается). Для ветки 7.x-2.x потребуется PHP версии 7.0 или выше.

Настройка

Страница настроек модуля позволяет:

    Задать учётные данные для выполнения авторизованных запросов к API; Включить тестовый режим (все запросы будут отправляться на тестовый сервер); Задать таймаут для запросов к API; Включить кэширование данных (список ПВЗ); Задать время хранения кэша.

Базовое использование

Основа модуля — это сервис cdek_api. Рассмотрим ряд примеров:

$client = \Drupal::service('cdek_api')->getCdekClient();

Получаем объект клиента с учётом настроек. Далее с помощью клиента можно выполнить любой запрос, который описан в документации.


$points = \Drupal::service('cdek_api')->getPickupPoints();

Получаем список всех ПВЗ (пункт выдачи заказа). Если кэширование включено, то полученные данные будут сохранены в отдельном кэш-бине. Кроме того, независимо от настроек, все данные сохраняются в статическом кэше. Следует отметить, что полный список имеет большой объём. В случае хранения кэша в базе данных и при возникновении ошибки при его записи следует увеличить значение параметра innodb_log_file_size.


$request = new PvzListRequest();
$request->setCityId(435);
$request->setCash(TRUE);
$request->setDressingRoom(TRUE);
 
$points = \Drupal::service('cdek_api')->getPickupPoints($request);

При запросе ПВЗ можно использовать фильтры. Для этого нужно в метод передать объект запроса с нужными параметрами. Списки с использованием фильтров также кэшируются.


$point = \Drupal::service('cdek_api')->getPickupPoint('KSD11');

Получаем конкретный ПВЗ по его коду.


$service = \Drupal::service('cdek_api');
 
$countries = $service->getCountries();
$regions = $service->getRegions();
$cities = $service->getCities();

Получаем список доступных стран, регионов и городов. Данные списки строятся на основе списка ПВЗ, поэтому сами не кэшируются.


$request = new PvzListRequest();
$request->setCountryId(1);
 
$cities = \Drupal::service('cdek_api')->getCities($request);

Фильтры также доступны.


Если необходимо внести изменения в список ПВЗ, то нужно создать обработчик события cdek_api.pickup_points. Например, в указанном ниже примере название ПВЗ заменяется на его адрес.

<?php
 
namespace Drupal\example\EventSubscriber;
 
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\cdek_api\Event\PickupPointsEvent;
use Drupal\cdek_api\Event\CdekApiEvents;
 
/**
 * An example event subscriber.
 */
class ExampleEventSubscriber implements EventSubscriberInterface {
 
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      CdekApiEvents::PICKUP_POINTS => 'alterPickupPoints',
    ];
  }
 
  /**
   * React to a list of pickup points being loaded.
   *
   * @param \Drupal\cdek_api\Event\PickupPointsEvent $event
   *   The pickup points event.
   */
  public function alterPickupPoints(PickupPointsEvent $event) {
    $points = $event->getPoints();
 
    foreach ($points as $point) {
      $point->Name = $point->Address;
    }
    $event->setPoints($points);
  }
 
}

В Drupal 7 сервисов и событий нет, поэтому код для 7.x-2.x будет отличаться.

Нужно обращаться напрямую к классу…

$client = CdekApi::getInstance()->getCdekClient();

…и вместо обработки события использовать реализацию хука hook_cdek_api_pickup_points_alter().

/**
 * Implements hook_cdek_api_pickup_points_alter().
 */
function example_cdek_api_pickup_points_alter(array &$points, array $params) {
  foreach ($points as $point) {
    $point->Name = $point->Address;
  }
}

Элемент формы для выбора ПВЗ

Модуль предоставляет два элемента формы, первый из которых — это элемент для иерархического выбора ПВЗ относительно выбранных значений страны/региона/города.

Чтобы использовать элемент, достаточно внутри формы указать следующий код:

$form['point'] = [
  '#type' => 'cdek_select',
];

Можно использовать стандартные свойства, применимые к стандартным элементам — #title, #description, #required и другие. Значением элемента при сабмите формы будет код выбранного ПВЗ. Можно также указывать значение по умолчанию с помощью #default_value, которое должно являться кодом существующего ПВЗ.

Кроме того, для изменения поведения и/или отображения элемента можно использовать дополнительное свойство #cdek_request, в котором нужно будет передать объект запроса аналогично тому как это используется в методе getPickupPoints() для фильтрации списка. Таким образом, можно изменять список ПВЗ, который будет доступен для выбора.

При этом, если в запросе указан фильтр по городу, то не будут отображаться элементы для выбора города, региона и страны. Если указан фильтр по региону, то не будут отображаться элементы для выбора региона и страны. Если указан фильтр по стране, то не будет отображаться элемент для выбора страны.

По умолчанию элементы для выбора страны/региона/города/пункта являются выпадающими списками. Их отображение можно кастомизировать с помощью прямого указания их структуры.

$form['point'] = [
  '#type' => 'cdek_select',
  'country' => [
    '#type' => 'radios',
    '#title' => NULL,
  ],
  'region' => [
    '#access' => FALSE,
  ],
];

Виджет

Второй элемент представляет собой интеграцию с виджетом ПВЗ (https://widget.cdek.ru). На сайте СДЭК указано следующее описание виджета:

Виджет предназначен для отображения актуальной информации о пунктах самовывоза СДЭК с привязкой их к карте, возможностью расчета доставки (сроков и стоимости) для указанных габаритов товаров. Виджет может быть отображен как статичный элемент на странице, так и всплывающим окном.

Элемент может быть использован как внутри формы, так и внутри обычного рендер массива. Если элемент используется в контексте формы, то он предназначен для выбора ПВЗ и панель с выбором варианта доставки будет скрыта. Выбранный ПВЗ будет отображаться в дочернем элементе над виджетом. Если элемент используется вне формы, то виджет считается информационным и выбор ПВЗ в нём запрещён.

В рамках одной страницы рекомендуется использовать не более одного виджета, в противном случае поведение не известно. Чтобы использовать элемент, достаточно указать следующий код:

$form['point'] = [
  '#type' => 'cdek_widget',
  '#cdek_widget_options' => [
    'defaultCity' => 'Краснодар',
    'cityFrom' => 'Москва',
  ],
];

В свойстве #cdek_widget_options указывается массив настроек виджета. Подробнее о настройках можно прочитать в документации виджета. Настройки link и servicepath указывать бессмысленно, так как они будут перезаписаны. Если указать настройку popup со значением TRUE, то виджет будет отображён в виде всплывающего окна.

К элементу применимы стандартные свойства элементов формы. Значение по умолчанию должно являться кодом существующего ПВЗ.

С помощью свойства #cdek_widget_popup_title можно задать текст ссылки, нажатие которой приводит к открытию виджета в режиме всплывающего окна.

Свойство #cdek_widget_tariff_list предназначено для указания списка тарифов, который будет использован контроллером виджета при расчёте стоимости для каждого из типов доставки (courier или pickup). Если список тарифов не указан, то для расчёта будет использован тариф под номером 1. Для того, чтобы контроллер мог получить доступ к тарифам, список сохраняется в кэше.

$form['point'] = [
  '#type' => 'cdek_widget',
  '#cdek_widget_options' => [
    'defaultCity' => 'Краснодар',
    'cityFrom' => 'Москва',
  ],
  '#cdek_widget_tariff_list' => [
    'courier' => [233, 137, 139, 16, 18, 11, 1, 3, 61, 60, 59, 58, 57, 83],
    'pickup' => [234, 136, 138, 15, 17, 10, 12, 5, 62, 63],
  ],
];

На данный момент модуль не имеет перевода на русский язык, поэтому все обозначения и описания внутри виджета отображаются на английском языке. Виджет можно локализовать вручную - все строки для перевода находятся в методе WidgetController::doActionLang(). В случае Drupal 7 - это функция cdek_api_widget_action_lang().

Элемент виджета также предоставляет API со стороны JavaScript. В процессе работы виджета возникают события: cdekApiWidgetReady, cdekApiWidgetDeliveryCalculated, cdekApiWidgetPointSelected и cdekApiWidgetCourierSelected. Они соответствуют событиям onReady, onCalculate, onChoose и onChooseProfile, которые описаны в документации виджета. Отличие заключается в отсутствии привязки к объекту виджета, так как событие вызывается для оболочки элемента. Соответственно, подписаться на событие можно с помощью стандартных средств jQuery.

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