Контролируйте количество результатов вызова API Magento

У меня есть программа, которую мы используем для подключения нашего магазина Magento к нашей системе управления запасами через API. В настоящее время он выполняет запрос API Magento для всех заказов в состоянии ожидания, вставляет их в заднюю систему, а затем устанавливает их статус "Обработка в Magento". Из-за ограничений в нашей системе инвентаризации мы можем вставлять только ограниченное количество заказов за раз. Мы контролируем это, запустив весь процесс через цикл if, как показано ниже (FYI, код был отредактирован для отображения только ключевых частей этой проблемы):

//The maximum number of orders to download
$iMaxCount = 10 ;

try {
  $proxy = new SoapClient($wsdl_url);
} catch (Exception $e) {
  echo 'Caught exception: ',  $e->getMessage(), "\n";
}

$sessionId = $proxy->login($login, $password);

//fetch the pending orders from the site
$field = array(array('status'=>array( 'pending') ));
$arr = $proxy->call($sessionId, 'sales_order.list', $field);
$iCnt = 0;

foreach($arr as $key => $value){
//only down up to the max count
if ($iCnt < $iMaxCount) {

[... Do the updating and insertion part of the program ...]

   $iCnt++;
} //End of looping through orders

Очевидное падение этого пути - мне все равно придется вытащить все отложенные ордера, хотя я буду работать только с 10 из них. т.е. если у меня есть 200 отложенных ордеров, API возвращает все 200 из них, обрабатывает 10, а затем пропускает остальные. То, что я хочу сделать, - это изменить фильтр вызова API, чтобы вывести только 10 заказов во время обработки статуса. Это позволит мне удалить накладные расходы if и сделать программу более эффективной, поскольку она получает только нужные ему данные.

Кто-нибудь знает, как применить этот тип фильтра? Все, что я видел, предполагает, что вы можете сделать это только в том случае, если знаете номера заказов и установите ограничения на основе этого. Спасибо за помощь!

Ответ 1

Все вызовы API, в конечном счете, просто исполняются PHP-кодом. Там будет один метод PHP, который принимает аргументы, переданные через вызов API, поэтому лучше всего отслеживать, где выполняется этот PHP-код.

Шаг 1 - найти конфигурацию вызова API. В современных версиях Magento конфигурации API хранятся в файлах с именем api.xml

$ find app/code/core/Mage/ -name 'api.xml'
app/code/core/Mage/Api/etc/api.xml
app/code/core/Mage/Catalog/etc/api.xml
app/code/core/Mage/CatalogInventory/etc/api.xml
app/code/core/Mage/Checkout/etc/api.xml
app/code/core/Mage/Customer/etc/api.xml
app/code/core/Mage/Directory/etc/api.xml
app/code/core/Mage/GiftMessage/etc/api.xml
app/code/core/Mage/Sales/etc/api.xml

Как только вы найдете все файлы api.xml, выполните поиск через них, чтобы настроить, какой из них "пространство имен api верхнего уровня" (неуверенный, что это действительно вызвано внутренними разработчиками).

$ find app/code/core/Mage/ -name 'api.xml' | xargs grep sales_order
app/code/core/Mage/Sales/etc/api.xml:            <sales_order translate="title" module="sales">
app/code/core/Mage/Sales/etc/api.xml:            </sales_order>
app/code/core/Mage/Sales/etc/api.xml:            <sales_order_shipment>
app/code/core/Mage/Sales/etc/api.xml:            </sales_order_shipment>
app/code/core/Mage/Sales/etc/api.xml:            <sales_order_invoice>
app/code/core/Mage/Sales/etc/api.xml:            </sales_order_invoice>
app/code/core/Mage/Sales/etc/api.xml:            <order>sales_order</order>
app/code/core/Mage/Sales/etc/api.xml:            <order_shipment>sales_order_shipment</order_shipment>
app/code/core/Mage/Sales/etc/api.xml:            <order_invoice>sales_order_invoice</order_invoice>

Похоже, что app/code/core/Mage/Sales/etc/api.xml - это файл, который мы хотим, так как он имеет тег <sales_order />. Затем откройте файл и посмотрите на <sales_order /> node.

<sales_order translate="title" module="sales">
    <model>sales/order_api</model>
    <title>Order API</title>
    <acl>sales/order</acl>
    <methods>
        <list translate="title" module="sales">
            <title>Retrieve list of orders by filters</title>
            <method>items</method>
            <acl>sales/order/info</acl>
        </list>
        <info translate="title" module="sales">
            <title>Retrieve order information</title>
            <acl>sales/order/info</acl>
        </info>

Первый node, нас интересует <model>sales/order_api</model>. Это указывает объект, который будет создан для обработки любого вызова API в пространстве имен sales_order.

Далее мы рассмотрим метод list в <methods/> node.

<list translate="title" module="sales">
    <title>Retrieve list of orders by filters</title>
    <method>items</method>
    <acl>sales/order/info</acl>
</list>

Этот node говорит нам, что вызов sales_order.list соответствует методу items. Объединив это с информацией, найденной выше, теперь мы знаем, что вызов API sales_order.list будет запускать PHP-код, эквивалентный следующему

$m = Mage::getModel('sales/order_api');
$results = $m->items($args);

Затем откройте файл модели и посмотрите на метод items

#File: app/code/core/Mage/Sales/Model/Order/Api.php
public function items($filters = null)
{
    //..a bunch of code to instantiate a collection object..
    if (is_array($filters)) {
        try {
            foreach ($filters as $field => $value) {
                if (isset($this->_attributesMap['order'][$field])) {
                    $field = $this->_attributesMap['order'][$field];
                }

                $collection->addFieldToFilter($field, $value);
            }
        } catch (Mage_Core_Exception $e) {
            $this->_fault('filters_invalid', $e->getMessage());
        }
    }        
}

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

Итак, это оставляет вам три варианта. Первый - найти набор значений для перехода в

$collection->addFieldToFilter($field, $value);

который ограничит вашу коллекцию. Мое предложение было бы каким-то фильтром даты, используя синтаксис array('from'=>'10','to'=>'20').

Вторым вариантом будет создание перезаписи класса для Mage_Sales_Model_Order_Api::items, которая выполняет некоторую дополнительную фильтрацию.

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

Ответ 2

Быстрое решение установить ограничение - найти приложение/код/​​ядро ​​/Маг/Продажи/Модель/Заказ/Api.php(и сделать переписку с классом), затем:

Измените подпись метода, чтобы принять другой параметр $limit, поэтому подпись метода выглядит следующим образом:

public function items($filters = null, $limit = null)

Затем добавьте следующую строку перед "foreach ($ orderCollection as $order) {":

if( $limit ) $orderCollection->setPageSize( $limit );

Затем просто передайте лимит в качестве дополнительного аргумента для вызова api sales_order.list.

Booyah!

Ответ 3

Вы должны иметь возможность использовать setPage, который устанавливает предложение LIMIT запроса, указывая номер страницы (одноиндексированный) и количество записей на странице.

$collection->setPage($pageNum, $pageSize);

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

$collection->setPage(2, 10);

Более подробную информацию по этой теме можно найти здесь: Использование коллекций в Magento