Closed vimbatu closed 2 years ago
Добрый вечер. Проверил с помощью вашего сниппета без изменений - фильтры отработали корректно. Рекомендую проверить результат с такими же фильтрами напрямую используя Postman или любой другой подобный инструмент. URL запроса для вашего сниппета будет выглядеть примерно так:
https://{{ домен системы }}/api/v5/store/products?apiKey={{ API-ключ }}&filter%5Bactive%5D=1&filter%5BexternalId%5D=9460&page=1&limit=100
Если результат ответа из системы будет аналогичен получаемому из клиента, то стоит обратиться в техподдержку.
Сделал запрос curl'ом:
$url_crm = 'https://{{ домен системы }}/api/v5/store/products?apiKey={{ API-ключ }}&filter%5Bactive%5D=1&filter%5BexternalId%5D=9460&page=1&limit=100'; $curl_crm = curl_init(); curl_setopt($curl_crm, CURLOPT_URL, $url_crm);
$crm = curl_exec($curl_crm);
Без проблем ответ вернулся с результатами фильтрации.
Для дополнительного разбора потребуются данные запроса в том виде, в котором они передаются клиентом. Чтобы их получить инициализируйте API-клиент следующим образом:
use RetailCrm\Api\Builder\ClientBuilder;
use RetailCrm\Api\Builder\FormEncoderBuilder;
use RetailCrm\Api\Handler\Request\HeaderAuthenticatorHandler;
use Psr\Log\AbstractLogger;
$client = (new ClientBuilder())
->setApiUrl('здесь URL системы')
->setAuthenticatorHandler(new HeaderAuthenticatorHandler('здесь API-ключ'))
->setFormEncoder((new FormEncoderBuilder())->build())
->setDebugLogger(new class extends AbstractLogger {
public function log($level, $message, array $context = [])
{
printf('[%s] %s %s' . PHP_EOL, $level, $message, json_encode($context));
}
})
->build();
Затем выполните запрос этим клиентом (выводить результат отдельно не нужно). В терминал будут выведены как данные запроса, так и данные ответа. Если фильтр не сработает и URL запроса корректный (содержит фильтр), то необходимо обратиться в техподдержку т.к. для повторения ситуации потребуются данные доступа к вашей системе.
Получил результаты. Есть некоторое отличие в запросах:
//запрос с нерабочим фильтром через клиент https://{{ домен системы }}/api/v5/store/products?filter%255Bactive%255D=1&filter%255BexternalId%255D=9460&limit=100
//запрос с рабочим фильтром через curl https://{{ домен системы }}/api/v5/store/products?filter%5Bactive%5D=1&filter%5BexternalId%5D=9460&page=1&limit=100
Я так понимаю, в урле запроса значения фильтра должны быть в [ ], а клиент по какой-то причине квадратные скобки меняет на юникод символ U+255B.
Может подскажете, в каком файле/классе формируется урл запроса, я сам гляну?
Формирование query string для запроса производится в компоненте FormEncoder. Сформированные данные в итоге используются в middleware RequestDataHandler. Однако, здесь клиент их уже никак не обрабатывает - они просто передаются в метод withQuery
компонента, имплементирующего UriInterface.
Похоже, что используемая вами имплементация UriInterface
работает некорректно. Согласно описанию в самом интерфейсе, UriInterface::withQuery
должен определять наличие символов, подлежащих кодировке в query string, и если таковых нет - не выполнять кодирование. Однако, используемая вами имплементация безальтернативно кодирует символы.
Проверить эту гипотезу можно выполнив следующий код:
print_r((string) \Http\Discovery\Psr17FactoryDiscovery::findUriFactory()->createUri('https://example.com/?filter%5B0%5D'));
Если выходная строка не идентична входной, то ваш UriInterface
работает некорректно. Если это так, то рекомендую использовать nyholm/psr7 вместо присутствующей у вас имплементации. Достаточно установить этот пакет - API-клиент должен начать находить его вместо существующей имплементации.
Проверить, что в клиенте начали использоваться фабрики из nyholm/psr7
можно выполнив следующий код:
print_r(get_class(\Http\Discovery\Psr17FactoryDiscovery::findUriFactory()));
Если выводится текст Nyholm\Psr7\Factory\Psr17Factory
, то все должно заработать корректно. Если же до сих пор используется другая имплементация - можно заставить клиент использовать нужную инициализируя его через ClientBuilder
(используя методы setStreamFactory
, setRequestFactory
и setUriFactory
). В таком случае для удобства работы с клиентом в приложении рекомендую реализовать свою фабрику для создания клиента, которая будет использовать ClientBuilder
(по аналогии с SimleClientFactory
).
Проверил, UriInterface работает некорректно. Кстати, есть мысли, с чем это может быть связано? nyholm/psr7 установил, сам он не подцепился, выводится Phalcon\Http\Message\UriFactory Подключил на странице: use Nyholm\Psr7; use Nyholm\Psr7\Factory; Подскажете правильный синтаксис, как указать ему другую имплементацию?
$client = (new ClientBuilder()) ->setApiUrl(' урл ') ->setAuthenticatorHandler(new HeaderAuthenticatorHandler(' ключ ')) ->setFormEncoder((new FormEncoderBuilder())->build()) ->setStreamFactory( ??? ) //так не работает ->setRequestFactory( ??? ) //так не работает ->setUriFactory( ??? ) //так не работает ->setDebugLogger(new class extends AbstractLogger { public function log($level, $message, array $context = []) { printf('[%s] %s %s' . PHP_EOL, $level, $message, json_encode($context)); } }) ->build();
Спасибо.
Проверил, UriInterface работает некорректно. Кстати, есть мысли, с чем это может быть связано?
Судя по всему, вы используете Phalcon. Вероятно, стоит уточнить причины такой реализации у авторов фреймворка.
Вот рабочий пример инициализации с другими фабриками.
<?php
require_once __DIR__ . '/vendor/autoload.php';
use RetailCrm\Api\Builder\ClientBuilder;
use RetailCrm\Api\Builder\FormEncoderBuilder;
use RetailCrm\Api\Handler\Request\HeaderAuthenticatorHandler;
use Tuupola\Http\Factory\RequestFactory;
use Tuupola\Http\Factory\StreamFactory;
use Tuupola\Http\Factory\UriFactory;
use Http\Client\Curl\Client;
$client = (new ClientBuilder())
->setApiUrl('https://test.retailcrm.pro')
->setAuthenticatorHandler(new HeaderAuthenticatorHandler('API-ключ'))
->setFormEncoder((new FormEncoderBuilder())->build())
->setStreamFactory(new StreamFactory())
->setRequestFactory(new RequestFactory())
->setUriFactory(new UriFactory())
->setHttpClient(new Client())
->build();
Спасибо большое, решение подошло.
use RetailCrm\Api\Enum\NumericBoolean, RetailCrm\Api\Factory\SimpleClientFactory, RetailCrm\Api\Interfaces\ApiExceptionInterface, RetailCrm\Api\Model\Filter\Store\ProductFilterType, RetailCrm\Api\Model\Request\Store\ProductsRequest;
$client = SimpleClientFactory::createClient('сайт', 'ключ');
$request = new ProductsRequest(); $request->filter = new ProductFilterType(); $request->filter->active = NumericBoolean::TRUE; $request->filter->externalId = '9460'; $request->page = 1; $request->limit = 100;
try { $response = $client->store->products($request); } catch (ApiExceptionInterface $exception) { echo sprintf( 'Error from RetailCRM API (status code: %d): %s', $exception->getStatusCode(), $exception->getMessage() ); if (count($exception->getErrorResponse()->errors) > 0) { echo PHP_EOL . 'Errors: ' . implode(', ', $exception->getErrorResponse()->errors); } return; }
echo 'Products: ' . "
";Не работает фильтрация элементов. При любых значениях фильтра все равно выводится полный список товаров. В чем может быть причина?