START UPDATE 2019-11-18
Заметил, что статья до сих пор для кого то служит источником информации.
Я сделал рефакторинг что бы сделать код более прямолинейным. По пути поправил пару досадных багов.
FINISH UPDATE 2019-11-18
Есть такой способ самообучения — как выполнение тестовых заданий. Его преимущество в том что объём задания конечен, сроки ограничены. Это не позволяет тянуть резину до бесконечности или самозабвенно вырисовывать завихрения и завитушки архитектурных изысков.
Приятный бонус такой тренировки скиллов заключается в знакомстве с новыми технологиями и бизнес процессами, которое кроме всего прочего востребованы в реальных задачах.
На этот раз надо было сделать страничку для формирования заказа покупателя в сервисе «Мой склад». Для меня это как полёт на Луну: в веб разработке я чуть меньше чем новичок, с фронтэндом знаком только по наслышке, а тут целую страницу надо разработать, ох ты Йожик!
Любая критика и советы приветствуются.
В коментах очень много ругательств, моё решение настолько ужасно, что для него сделали рефакторинг во что то приличное:
michael_vostrikov
Первым делом конечно гуглить, нагуглилась только ссылка на документацию, туториалов, примеров — ноль.
Ещё нагуглилось: «JSON API доступен для подписчиков на всех тарифах, кроме Бесплатного» уупс! Платного мне конечно ни кто не дал, покупать не камильфо, но я подумал что если дали такое задание, то наверное на Бесплатном что то там функционирует и продолжил работу.
И конечно нагуглилось «moysklad-client — npm — JavaScript клиент для комфортной работы с API сервиса МойСклад», но я с JS исключительно на «Вы», и по условиям задания, написать надо на PHP. Так что даже разбираться не стал, что там на JS можно делать.
Первое что надо сделать, это познакомиться с документацией. Познакомился.
Второе — составить план. Составил.
План, начало.
Действие первое — авторизация.
Действие второе — показать список Номенклатур.
Действие третье — добавить Заказ покупателя.
Действие четвёртое — добавить Позиции в Заказ покупателя.
Цель достигнута, конец плана.
Я видел код в котором для общения с API использовался cUrl. Я не знаю что такое cUrl, я не знаю как принято общаться с API, но если есть код который можно скопипастить, то проверить его пригодность не сложно. Скопировал вставил, обработал напильником — получилось.
Не буду утомлять вас интимными подробностями о дружбе напильника с копипастой, вот работающий код:
Параметры curl:
Остальные опции не знаю зачем нужны, тупо копипаста.
Не факт, что заголовки авторизации надо отправлять в каждом запросе, хотя не факт, что они не сбросились после первой же отправки… кто подскажет?
Итак, это была инициализация объекта curl для обмена сообщениями с сервером API.
Использование:
Чистая копипаста, не спрашивайте меня почему так.
Одних номенклатур оказалось мало, для Заказа покупателя, надо указать юридическое лицо Поставщика и контрагента Покупателя. У владельца учётки «Мой склад» может быть несколько юридических лиц, контрагентов — ясно понятно 100500, но конкретный Заказ покупателя, это заказ конкретного Контрагента в адрес конкретного Юридического лица.
Поэтому с номенклатурами обождём, займёмся сторонами «договора» — сделки.
Юридические лица
Извиняюсь за ужасные названия констант, но мне с такими спокойней, точно ни с чем не перепутаю. Да я знаю что у case (switch) есть ветка default, но мне спокойней вбетонировать в код значение по умолчанию и не надеяться на превратности судьбы с case.
У каждой команды API свой адрес и свой метод, setCurl — устанавливает адрес и метод.
Для получения списка юридических лиц устанавливаем соответствующий адрес и метод ( адрес и метод задаются в настройках, настройки подгружаются методом function getSettings(){ $apiConfig = include('moysklad_curl_details.php'); return $apiConfig;} ).
После этого методом getJuridicalPerson исполняем curl, получаем ответ в JSON, из ответа забираем только массив 'rows'. Получили, сохранили, отложили.
С Контрагентами поступаем аналогично: setCurl => getCounterparty, Номенклатуры по тому же алгоритму: setCurl => getNomenclature.
Если бы это было не тестовое на два вечера после работы, а на два дня безработного специалиста, то можно было бы это автоматизировать, но это было тестовое в стиле — «лишь бы работало», поэтому я не стал изгаляться.
Для меня цель тестового была в том что бы пригубить и попробовать на вкус JSON API, рисовать красоту — цели не было.
Данные получили — это вообще не вопрос, дело дурацкое — дело не хитрое, интересней было как то это вывести на страничку, а потом со странички забрать, вот это была задачка.
Не знаю как правильно, я сделал так:
Общий алгоритм:
(вообще конечно можно использовать атрибуты без значений, но я не разобрался как).
По клику на кнопку «Сформировать заказ покупателя», форма не отправляется — «return false;», но вызывается функция — «sendOrder();».
C JS мне кажется всё более чем прозрачно:
Проделываем такую же акробатику с юридическими лицами и контр агентами, с тем отличием что для анализа выбираем все input с типом «radio» в состоянии «checked»:
$('#orderForm :input:radio:checked'), и кроме того значение элемента input нам не требуется, нам просто надо знать кого ( одного ) из всего списка выбрал наш Покупатель.
Теперь когда данные для отправки в обработку готовы, надо сформировать запрос:
К этой копипасте мне добавить не чего, метод отправки — «POST», обработка будет выполнена — «moyskald_add_order.php», данные уходят в формате -«application/json; charset=utf-8», приходят в формате — «text».
Данные вообще не нужны, хотя конечно хороший тон это сообщить пользователю «Ваш заказ принят» или «Сбой добавления заказа», и ладно.
Едем дальше, следующий пункт прибытия — «Обработка».
С обработкой вышла осечка. Я ламер-эникейщик и для разработки использую XAMPP (под Win10), который как то раз настроил и забыл. И вот что то там такое настроено, что я GET запросы в PHP-скрипт получаю как нормальный человек, а POST-запросы, только через одно место.
Но GET — не камильфо, потому что GET кэшуруется, а у нас не факт что ответ сервера будет точно таким как в прошлый раз, особенно когда ты ведёшь разработку, и серверная логика меняется каждые пять минут.
Поэтому пришлось смириться с использованием чёрной магии в виде file_get_contents(«php://input»), потому что, что бы я ни делал, но var_export($POST) стабильно выдавал «array()». Между прочим, буду благодарен за серию пинков в верном направлении.
А дальше всё просто:
Разобрали входные данные.
Дёрнули Юридическое лицо и контрагента:
Сформировали поля запроса:
Тут получилось схалявить и зафигачить JSON без json_encode, тупо вклеить нужные идентификатору, в нужные места. Обязательно делаем POSTFIELDS — $textAddCustomerOrder, HTTPHEADER — 'Content-Length: '. strlen($textAddCustomerOrder).
отправляем запрос на обработку на сервер API: $customerOrderId = setCustomerOrder($curl), в ответе забираем 'id'.
Заказ добавлен.
С этим пунктом Плана, ни каких проблем, кроме необходимости использования json_encode для форматирования текста запроса и floatval для количества товара в позиции. Без floatval сервер API выдаёт ошибку формата для поля «quantity» (и «reserve» соответственно).
Ремарка: foreach ($rawPosition as $id => $quantity), в ключах массива записаны идентификаторы позиций, в значениях элементов массива — количество для заказа.
Мой фэншуй требует создания каждого массива по отдельности и добавления всех «элементарных» массивов в общую кучу, но… мне кажется это будет излишний фанатизм.
Не уверен что в заказе покупателя надо выставлять резерв, но мне кажется это больше бизнес требование, чем механика работы с API.
С ценой смешно вышло, в задании требовалось вывести список номенклатур, для меня это просто перечень наименований и соответствующих ТТХ, в которые цена не входит, но если подумать, то цена это самое первое ТТХ в подобном приложении, но у меня в форме заказа цены нет, поэтому — проехали.
С отправкой API запроса теперь мне кажется всё предельно ясно:
Адрес-команда запроса «вычисляется» несколько странным образом:
По документации должно быть :"/entity/customerorder/{id}/positions".
Типа даже нативная PHP строка, бери да прямо так и пиши — {id} подставиться само, но я не могу допустить хардкода в отношении записи команды API, нет конечно за время написания тестового команда не поменяется, но феншуй требует такие глобальные вещи выносить в константы, аминь. Хотя когда я смотрю на исходники всяких open source фреймворков, я вижу что хардкод там сплошь и рядом, но это делают они, а это делаю я, и я так не делаю.
Вот собственно и всё. API, на Бесплатном тарифе, обрабатывает запросы в последнюю очередь, поэтому иногда таймаута в 10 секунд не достаточно. В остальном работает стабильно. Я проверял.
Но наша цель конечно была не в этом, в результате выполнения задания, мы научились работать с JSON Web API и научились мутить фронтэнд с выводом информации в форму и передачей пользовательского ввода для обработки в серверный скрипт.
Ура :)
Перед написанием статьи я чуть плотнее погуглил на тему «php json api мой склад» и нашёл массу реализаций, но не для JSON, а для XML. Из десятка найденных, парочка похожа на реально рабочие, но это не актуально потому что XML API грозятся отключить с 31 марта 2017.
А может всё будет так же как с «JSON API доступен для подписчиков на всех тарифах, кроме Бесплатного».
Конструктивная критика и ссылки на best practics ПРИВЕТСТВУЮТСЯ! мне не стыдно быть колхозником, но не хорошо бы если лучше?
Заметил, что статья до сих пор для кого то служит источником информации.
Я сделал рефакторинг что бы сделать код более прямолинейным. По пути поправил пару досадных багов.
FINISH UPDATE 2019-11-18
Есть такой способ самообучения — как выполнение тестовых заданий. Его преимущество в том что объём задания конечен, сроки ограничены. Это не позволяет тянуть резину до бесконечности или самозабвенно вырисовывать завихрения и завитушки архитектурных изысков.
Приятный бонус такой тренировки скиллов заключается в знакомстве с новыми технологиями и бизнес процессами, которое кроме всего прочего востребованы в реальных задачах.
На этот раз надо было сделать страничку для формирования заказа покупателя в сервисе «Мой склад». Для меня это как полёт на Луну: в веб разработке я чуть меньше чем новичок, с фронтэндом знаком только по наслышке, а тут целую страницу надо разработать, ох ты Йожик!
Любая критика и советы приветствуются.
В коментах очень много ругательств, моё решение настолько ужасно, что для него сделали рефакторинг во что то приличное:
michael_vostrikov
От нечего делать сделал небольшой рефакторинг этого задания (хотя там много чего еще можно поменять), не столько для вас, сколько для тех, кто потом найдет в поиске эту статью:
коммиты, разметка, отправка формы.
Поехали!
Первым делом конечно гуглить, нагуглилась только ссылка на документацию, туториалов, примеров — ноль.
Ещё нагуглилось: «JSON API доступен для подписчиков на всех тарифах, кроме Бесплатного» уупс! Платного мне конечно ни кто не дал, покупать не камильфо, но я подумал что если дали такое задание, то наверное на Бесплатном что то там функционирует и продолжил работу.
И конечно нагуглилось «moysklad-client — npm — JavaScript клиент для комфортной работы с API сервиса МойСклад», но я с JS исключительно на «Вы», и по условиям задания, написать надо на PHP. Так что даже разбираться не стал, что там на JS можно делать.
Первое
Первое что надо сделать, это познакомиться с документацией. Познакомился.
Второе — составить план. Составил.
План, начало.
Действие первое — авторизация.
Действие второе — показать список Номенклатур.
Действие третье — добавить Заказ покупателя.
Действие четвёртое — добавить Позиции в Заказ покупателя.
Цель достигнута, конец плана.
Авторизация
Я видел код в котором для общения с API использовался cUrl. Я не знаю что такое cUrl, я не знаю как принято общаться с API, но если есть код который можно скопипастить, то проверить его пригодность не сложно. Скопировал вставил, обработал напильником — получилось.
Не буду утомлять вас интимными подробностями о дружбе напильника с копипастой, вот работающий код:
function setupCurl($apiSettings)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
$userName = $apiSettings[MOYSKLAD_USERNAME];
$userPassword = $apiSettings[MOYSKLAD_PASSWORD];
curl_setopt($curl, CURLOPT_USERPWD, "$userName:$userPassword");
curl_setopt($curl, CURLOPT_USERAGENT, $apiSettings[MOYSKLAD_USER_AGENT]);
return $curl;
}
Параметры curl:
- RETURNTRANSFER — не только отправляем запрос, но и записываем ответ;
- USERPWD — реквизиты аутентификации;
Остальные опции не знаю зачем нужны, тупо копипаста.
Не факт, что заголовки авторизации надо отправлять в каждом запросе, хотя не факт, что они не сбросились после первой же отправки… кто подскажет?
Итак, это была инициализация объекта curl для обмена сообщениями с сервером API.
Использование:
function curlExec($curlObject)
{
$response = curl_exec($curlObject);
$curlErrorNumber = curl_errno($curlObject);
if ($curlErrorNumber) {
throw new Exception(curl_error($curlObject));
}
return $response;
}
Чистая копипаста, не спрашивайте меня почему так.
Показать список Номенклатур
Одних номенклатур оказалось мало, для Заказа покупателя, надо указать юридическое лицо Поставщика и контрагента Покупателя. У владельца учётки «Мой склад» может быть несколько юридических лиц, контрагентов — ясно понятно 100500, но конкретный Заказ покупателя, это заказ конкретного Контрагента в адрес конкретного Юридического лица.
Поэтому с номенклатурами обождём, займёмся сторонами «договора» — сделки.
Юридические лица
$curl = setCurl(
$curl,
$apiSettings[MOYSKLAD_API_URL] . $apiSettings[MOYSKLAD_GET_JURIDICAL_PERSON],
$apiSettings[MOYSKLAD_GET_JURIDICAL_PERSON_METHOD]);
$persons = getJuridicalPerson($curl);
function setCurl(&$curlObject, $uri, $method)
{
curl_setopt($curlObject, CURLOPT_URL, $uri);
curl_setopt($curlObject, CURLOPT_HTTPGET, true);
switch ($method) {
case MOYSKLAD_METHOD_GET:
break;
case MOYSKLAD_METHOD_POST:
curl_setopt($curlObject, CURLOPT_POST, true);
break;
case MOYSKLAD_METHOD_PUT:
curl_setopt($curlObject, CURLOPT_PUT, true);
break;
}
return $curlObject;
}
function getJuridicalPerson($curlObject)
{
$response = curlExec($curlObject);
$data = json_decode($response, true);
$result = $data['rows'];
return $result;
}
Извиняюсь за ужасные названия констант, но мне с такими спокойней, точно ни с чем не перепутаю. Да я знаю что у case (switch) есть ветка default, но мне спокойней вбетонировать в код значение по умолчанию и не надеяться на превратности судьбы с case.
У каждой команды API свой адрес и свой метод, setCurl — устанавливает адрес и метод.
Для получения списка юридических лиц устанавливаем соответствующий адрес и метод ( адрес и метод задаются в настройках, настройки подгружаются методом function getSettings(){ $apiConfig = include('moysklad_curl_details.php'); return $apiConfig;} ).
После этого методом getJuridicalPerson исполняем curl, получаем ответ в JSON, из ответа забираем только массив 'rows'. Получили, сохранили, отложили.
С Контрагентами поступаем аналогично: setCurl => getCounterparty, Номенклатуры по тому же алгоритму: setCurl => getNomenclature.
Если бы это было не тестовое на два вечера после работы, а на два дня безработного специалиста, то можно было бы это автоматизировать, но это было тестовое в стиле — «лишь бы работало», поэтому я не стал изгаляться.
Для меня цель тестового была в том что бы пригубить и попробовать на вкус JSON API, рисовать красоту — цели не было.
Данные получили — это вообще не вопрос, дело дурацкое — дело не хитрое, интересней было как то это вывести на страничку, а потом со странички забрать, вот это была задачка.
Фронтэнд
Не знаю как правильно, я сделал так:
echo '<form action="#" onsubmit="return false;" id="orderForm" ><p>Доступные юридические лица:<br />';
foreach ($persons as $key => $person) {
$personId = $person['id'];
echo '<label for="' . $personId . '">' . $person['name'] . '</label><input type="radio" data-organization-type="1" id="' . $personId . '" name="organization"><br />';
}
echo 'Доступные контрагенты:<br />';
foreach ($counterparty as $key => $person) {
$personId = $person['id'];
echo '<label for="' . $personId . '">' . $person['name'] . '</label><input type="radio" data-counterparty-type="1" id="' . $personId . '" name="counterparty"><br />';
}
echo 'Номенклатура товаров:<br />';
foreach ($nomenclature as $key => $position) {
$positionId = $position['id'];
echo '<label for="' . $positionId . '">' . $position['name'] . ', количество для заказа => </label><input type="text" id="' . $positionId . '" data-position-type="1"><br />';
}
echo '
<input type="submit" name="Сформировать заказ покупателя" onclick="sendOrder();"><br /></p></form>'
Общий алгоритм:
- пишем название раздела
- пишем название позиции,
- пишем тег input, в атрибут id пишем идентификатор полученный из API,
- пишем соответствующий атрибут data-organization-type / data-counterparty-type / data-position-type, поскольку для получения атрибута надо присвоить значение, то присваиваем
(вообще конечно можно использовать атрибуты без значений, но я не разобрался как).
По клику на кнопку «Сформировать заказ покупателя», форма не отправляется — «return false;», но вызывается функция — «sendOrder();».
Отправить заказ
echo '
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function sendOrder(){
var $text_field = $('#orderForm :input:text');
var position = {};
$text_field.each(function() {
var this_val = $(this).val();
var may_assign = this_val>0 || this_val !="";
var is_it_position = $(this).data('position-type');
if ( may_assign && is_it_position > 0){
position[this.id] = this_val;
}
});
var $radio_field = $('#orderForm :input:radio:checked');
var counterparty = {};
var organization = {};
$radio_field.each(function() {
var this_val = $(this).val();
var is_it_counterparty = $(this).data('counterparty-type');
var is_it_organization = $(this).data('organization-type');
var may_assign = this_val>0 || this_val !="";
if ( may_assign && is_it_counterparty > 0){
counterparty[this.id] = this_val;
}
if ( may_assign && is_it_organization > 0){
organization[this.id] = this_val;
}
});
C JS мне кажется всё более чем прозрачно:
- $('#orderForm :input:text'); — выбрали все теги input с типом text внутри тега с идентификатором orderForm
- $text_field.each — для каждого элемента выполняем анонимную функцию
- var this_val = $(this).val(); — сохранили значение
- var may_assign = this_val>0 || this_val !=""; — вычислили что значение не пустое
- var is_it_position = $(this).data('position-type'); — вычислили что атрибут data-position-type установлен
- if ( may_assign && is_it_position > 0){ position[this.id] = this_val; } — если значение не пустое и этот input соответствует позиции, то добавляем в массив позиций соответствующий элемент, идентификатор в качестве индекса гарантирует уникальность.
Проделываем такую же акробатику с юридическими лицами и контр агентами, с тем отличием что для анализа выбираем все input с типом «radio» в состоянии «checked»:
$('#orderForm :input:radio:checked'), и кроме того значение элемента input нам не требуется, нам просто надо знать кого ( одного ) из всего списка выбрал наш Покупатель.
Теперь когда данные для отправки в обработку готовы, надо сформировать запрос:
var postData = JSON.stringify({position : position, counterparty : counterparty , organization : organization});
console.log(postData);
$.ajax({
type: "POST",
url: "moyskald_add_order.php",
data: postData,
contentType: "application/json; charset=utf-8",
dataType: "text",
timeout: 10000,
error: function(){
alert("сбой добавления заказа");
},
success: function(data){alert(data);},
failure: function(errMsg) {
alert(errMsg);
}
});
К этой копипасте мне добавить не чего, метод отправки — «POST», обработка будет выполнена — «moyskald_add_order.php», данные уходят в формате -«application/json; charset=utf-8», приходят в формате — «text».
Данные вообще не нужны, хотя конечно хороший тон это сообщить пользователю «Ваш заказ принят» или «Сбой добавления заказа», и ладно.
Едем дальше, следующий пункт прибытия — «Обработка».
Обработка
С обработкой вышла осечка. Я ламер-эникейщик и для разработки использую XAMPP (под Win10), который как то раз настроил и забыл. И вот что то там такое настроено, что я GET запросы в PHP-скрипт получаю как нормальный человек, а POST-запросы, только через одно место.
Но GET — не камильфо, потому что GET кэшуруется, а у нас не факт что ответ сервера будет точно таким как в прошлый раз, особенно когда ты ведёшь разработку, и серверная логика меняется каждые пять минут.
Поэтому пришлось смириться с использованием чёрной магии в виде file_get_contents(«php://input»), потому что, что бы я ни делал, но var_export($POST) стабильно выдавал «array()». Между прочим, буду благодарен за серию пинков в верном направлении.
А дальше всё просто:
$data = json_decode($rawData, true);
$rawPosition = $data['position'];
$rawCounterparty = $data['counterparty'];
$rawOrganization = $data['organization'];
Разобрали входные данные.
Дёрнули Юридическое лицо и контрагента:
const FIRST_INDEX = 0;
$counterpartyId = $counterpartyIdCollection[FIRST_INDEX];
$organizationId = $organizationIdCollection[FIRST_INDEX];
Сформировали поля запроса:
$textAddCustomerOrder = '
{
"name": "' . time() . '",
"organization": {
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.1/entity/organization/' . $organizationId . '",
"type": "organization",
"mediaType": "application/json"
}
},
"agent": {
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.1/entity/counterparty/' . $counterpartyId . '",
"type": "counterparty",
"mediaType": "application/json"
}
}
}
';
$apiSettings = getSettings();
$curl = setupCurl($apiSettings);
$curl = setCurl(
$curl,
$apiSettings[MOYSKLAD_API_URL] . $apiSettings[MOYSKLAD_ADD_CUSTOMER_ORDER],
$apiSettings[MOYSKLAD_ADD_CUSTOMER_ORDER_METHOD]);
curl_setopt($curl, CURLOPT_POSTFIELDS, $textAddCustomerOrder);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($textAddCustomerOrder))
);
Тут получилось схалявить и зафигачить JSON без json_encode, тупо вклеить нужные идентификатору, в нужные места. Обязательно делаем POSTFIELDS — $textAddCustomerOrder, HTTPHEADER — 'Content-Length: '. strlen($textAddCustomerOrder).
отправляем запрос на обработку на сервер API: $customerOrderId = setCustomerOrder($curl), в ответе забираем 'id'.
Заказ добавлен.
Добавить Позиции в Заказ покупателя
С этим пунктом Плана, ни каких проблем, кроме необходимости использования json_encode для форматирования текста запроса и floatval для количества товара в позиции. Без floatval сервер API выдаёт ошибку формата для поля «quantity» (и «reserve» соответственно).
$isPositionArray = is_array($rawPosition);
$orderPositions= array();
if ($isPositionArray) {
foreach ($rawPosition as $id => $quantity) {
$positionQuantity=floatval($quantity);
$orderPositions[] =
[
"quantity" =>$positionQuantity,
"price"=>0,
"discount"=>0,
"vat"=>0,
"assortment" =>[
"meta"=>[
"href"=>"https://online.moysklad.ru/api/remap/1.1/entity/product/$id",
"type"=>"product",
"mediaType"=>"application/json"
]
],
"reserve"=>$positionQuantity,
];
}
}
Ремарка: foreach ($rawPosition as $id => $quantity), в ключах массива записаны идентификаторы позиций, в значениях элементов массива — количество для заказа.
Мой фэншуй требует создания каждого массива по отдельности и добавления всех «элементарных» массивов в общую кучу, но… мне кажется это будет излишний фанатизм.
Не уверен что в заказе покупателя надо выставлять резерв, но мне кажется это больше бизнес требование, чем механика работы с API.
С ценой смешно вышло, в задании требовалось вывести список номенклатур, для меня это просто перечень наименований и соответствующих ТТХ, в которые цена не входит, но если подумать, то цена это самое первое ТТХ в подобном приложении, но у меня в форме заказа цены нет, поэтому — проехали.
С отправкой API запроса теперь мне кажется всё предельно ясно:
$jsonResponse = 'empty';
$isContainPosition = count($orderPositions)>0;
if($isContainPosition ){
$jsonOrderPositions= json_encode($orderPositions);
$curl = setupCurl($apiSettings);
$curl = setCurl(
$curl,
$apiSettings[MOYSKLAD_API_URL]
. $apiSettings[MOYSKLAD_ADD_ORDER_POSITION_PREFIX]
. $customerOrderId
. $apiSettings[MOYSKLAD_ADD_ORDER_POSITION_SUFFIX],
$apiSettings[MOYSKLAD_ADD_ORDER_POSITION_METHOD]);
curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonOrderPositions);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonOrderPositions))
);
$jsonResponse = setCustomerOrderPosition($curl);
}
Адрес-команда запроса «вычисляется» несколько странным образом:
$apiSettings[MOYSKLAD_API_URL]
. $apiSettings[MOYSKLAD_ADD_ORDER_POSITION_PREFIX]
. $customerOrderId
. $apiSettings[MOYSKLAD_ADD_ORDER_POSITION_SUFFIX]
По документации должно быть :"/entity/customerorder/{id}/positions".
Типа даже нативная PHP строка, бери да прямо так и пиши — {id} подставиться само, но я не могу допустить хардкода в отношении записи команды API, нет конечно за время написания тестового команда не поменяется, но феншуй требует такие глобальные вещи выносить в константы, аминь. Хотя когда я смотрю на исходники всяких open source фреймворков, я вижу что хардкод там сплошь и рядом, но это делают они, а это делаю я, и я так не делаю.
Эпилог
Вот собственно и всё. API, на Бесплатном тарифе, обрабатывает запросы в последнюю очередь, поэтому иногда таймаута в 10 секунд не достаточно. В остальном работает стабильно. Я проверял.
Но наша цель конечно была не в этом, в результате выполнения задания, мы научились работать с JSON Web API и научились мутить фронтэнд с выводом информации в форму и передачей пользовательского ввода для обработки в серверный скрипт.
Ура :)
PostScriptum
Перед написанием статьи я чуть плотнее погуглил на тему «php json api мой склад» и нашёл массу реализаций, но не для JSON, а для XML. Из десятка найденных, парочка похожа на реально рабочие, но это не актуально потому что XML API грозятся отключить с 31 марта 2017.
А может всё будет так же как с «JSON API доступен для подписчиков на всех тарифах, кроме Бесплатного».
Конструктивная критика и ссылки на best practics ПРИВЕТСТВУЮТСЯ! мне не стыдно быть колхозником, но не хорошо бы если лучше?