将 CakePHP Http 客户端与 Magento2 rest API 搜索条件一起使用
Use CakePHP Http Client with Magento2 rest API search criteria
我正在尝试向本地 Magento2 rest API 发送 GET 请求以在特定时间后获取所有订单。我正在关注 http://devdocs.magento.com/guides/v2.1/howdoi/webapi/search-criteria.html#simple-search-using-a-timestamp. I'm using CakePHP 3.4's Http Client (https://book.cakephp.org/3.0/en/core-libraries/httpclient.html),并且已经使用 Oauth1 成功地与 Magento 集成,并且对 http://www.magento.dev.com/rest/V1/stockItems/:productSku
等更简单的 GET 请求没有任何问题。通过搜索条件是一个问题。响应始终是 401 Invalid Signature
.
使用 Postman,我可以获得对 http://www.magento.dev.com/rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=created_at&searchCriteria[filter_groups][0][filters][0][value]=2016-07-01 00:00:00&searchCriteria[filter_groups][0][filters][0][condition_type]=gt
的有效回复
这就是我所拥有的 far/how 我正在发送请求:
在Model/Table/OrdersTable.php:
public function importNewOrders(\App\Model\Entity\OauthIntegration $integrationDetails)
{
$this->OauthIntegrations = TableRegistry::get('OauthIntegrations');
$this->Orders = TableRegistry::get('Orders');
$timeCutOff = '2015-01-01 00:00:00';
$search = [
'searchCriteria' => [
'filterGroups' => [
0 => [
'filters' => [
0 => [
'field' => 'created_at',
'value' => $timeCutOff,
'condition_type' => 'gt'
]
]
]
]
]
];
// 'searchCriteria[filter_groups][0][filters][0][field]' => 'created_at',
// 'searchCriteria[filter_groups][0][filters][0][value]' => $timeCutOff,
// 'searchCriteria[filter_groups][0][filters][0][condition_type]' => 'gt'
$action = '/V1/orders';
$type = "GET";
$response = $this->OauthIntegrations->sendRequest(
$integrationDetails,
$action,
$type,
'',
$search);
Log::write('debug', $response->body());
return $response;
}
并在 Model\Table\OauthIntegrationsTable.php:
public function sendRequest(\App\Model\Entity\OauthIntegration $integrationDetails,
string $action, string $method = "GET", string $data = '', array $search = null)
{
$http = new Client([
'auth' => [
'type' => 'oauth',
'consumerKey' => $integrationDetails->oauth_consumer_key,
'consumerSecret' => $integrationDetails->oauth_consumer_secret,
'token' => $integrationDetails->oauth_token,
'tokenSecret' => $integrationDetails->oauth_token_secret
]
]);
$url = $integrationDetails->store_base_url . 'rest' . $action;
if ($method == 'GET'){
if (!isset($search)){
$search = [];
}
$response = $http->get($url, $search, []);
} else if ($method == 'POST'){
$response = $http->post($url, $data, [
'type' => 'json',
]);
} else if($method == 'PUT'){
$response = $http->put($url, $data, [
'type' => 'json',
]);
}
Log::write('debug', 'url: ' . $url . ' and status code: ' . $response->getStatusCode());
return $response;
}
这是错误(我希望)是无效签名响应的原因:
2017-03-28 10:07:01 Notice: Notice (8): Array to string conversion in [/var/www/cakephp/html/beacon/vendor/cakephp/cakephp/src/Http/Client/Auth/Oauth.php, line 315]
Trace:
Cake\Error\BaseErrorHandler::handleError() - CORE/src/Error/BaseErrorHandler.php, line 153
Cake\Http\Client\Auth\Oauth::_normalizedParams() - CORE/src/Http/Client/Auth/Oauth.php, line 315
Cake\Http\Client\Auth\Oauth::baseString() - CORE/src/Http/Client/Auth/Oauth.php, line 246
Cake\Http\Client\Auth\Oauth::_hmacSha1() - CORE/src/Http/Client/Auth/Oauth.php, line 143
Cake\Http\Client\Auth\Oauth::authentication() - CORE/src/Http/Client/Auth/Oauth.php, line 61
Cake\Http\Client::_addAuthentication() - CORE/src/Http/Client.php, line 501
Cake\Http\Client::_createRequest() - CORE/src/Http/Client.php, line 448
Cake\Http\Client::_doRequest() - CORE/src/Http/Client.php, line 341
Cake\Http\Client::get() - CORE/src/Http/Client.php, line 211
App\Model\Table\OauthIntegrationsTable::sendRequest() - APP/Model/Table/OauthIntegrationsTable.php, line 134
App\Model\Table\OrdersTable::importNewOrders() - APP/Model/Table/OrdersTable.php, line 672
App\Shell\MagentoShell::main() - APP/Shell/MagentoShell.php, line 36
Cake\Console\Shell::runCommand() - CORE/src/Console/Shell.php, line 472
Cake\Console\ShellDispatcher::_dispatch() - CORE/src/Console/ShellDispatcher.php, line 227
Cake\Console\ShellDispatcher::dispatch() - CORE/src/Console/ShellDispatcher.php, line 182
Cake\Console\ShellDispatcher::run() - CORE/src/Console/ShellDispatcher.php, line 128
[main] - ROOT/bin/cake.php, line 33
来自 Http\Client\Oauth.php 的代码发生错误的地方:
$pairs = [];
foreach ($args as $k => $val) {
if (is_array($val)) {
sort($val, SORT_STRING);
Log::write('debug', 'about to go through foreach($val as $nestedVal)');
foreach ($val as $nestedVal) {
Log::write('debug', $nestedVal);
$pairs[] = "$k=$nestedVal"; // <<< HERE
}
} else {
$pairs[] = "$k=$val";
}
}
从上面调试结果:
2017-03-28 10:07:01 Debug: about to go through foreach($val as $nestedVal)
2017-03-28 10:07:01 Debug: Array
(
[0] => Array
(
[filters] => Array
(
[0] => Array
(
[field] => created_at
[value] => 2015-01-01 00:00:00
[condition_type] => gt
)
)
)
)
综上所述,是否可以使用Cake的Http Client将多维数组传递给get请求中的第二个参数?
// Is it possible to replace ['q' => 'widget'] with a multi-dimensional array??
$response = $http->get('http://example.com/search', ['q' => 'widget']);
如果没有,使用 Cake 的 Http 客户端发送 GET 请求的最佳方式是什么:http://www.magento.dev.com/rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=created_at&searchCriteria[filter_groups][0][filters][0][value]=2016-07-01 00:00:00&searchCriteria[filter_groups][0][filters][0][condition_type]=gt
?
提前致谢!!!
可能存在错误
这可能被认为是一个错误。我认为 the OAuth specs 不会考虑 URL 中的这种 PHP 样式括号内容,因此 sorting/encoding 参数仅限于平面 key=value
集,即一个键是
searchCriteria[filter_groups][0][filters][0][field]
并且值为
created_at
然而,CakePHP OAuth 适配器将请求查询字符串解析为可能深度嵌套的数组结构,这将失败,因为它不处理这种情况。
我建议你 report this as a possible bug。进一步的问题可能会发生,因为编码似乎是在排序之前应用的,在 CakePHP 实现中,additonal 参数编码在排序之后应用(实际上可能没问题不过,我不确定)。
尝试使用自定义 OAuth 适配器作为解决方法
在此之前 fixed/enhanced,您可以使用自定义 OAuth 适配器来“正确”处理事情(无论在此上下文中意味着什么)。这是一个简单粗暴的例子(适用于我的 Magento API)。
创建src/Http/Client/Auth/AppOAuth.php
<?php
namespace App\Http\Client\Auth;
use Cake\Http\Client\Auth\Oauth;
class AppOAuth extends Oauth
{
protected function _normalizedParams($request, $oauthValues)
{
$query = parse_url($request->url(), PHP_URL_QUERY);
parse_str($query, $queryArgs);
$post = [];
$body = $request->body();
if (is_string($body) &&
$request->getHeaderLine('content-type') === 'application/x-www-form-urlencoded'
) {
parse_str($body, $post);
}
if (is_array($body)) {
$post = $body;
}
$args = array_merge($queryArgs, $oauthValues, $post);
$query = http_build_query($args);
$args = [];
foreach (explode('&', $query) as $value) {
$pair = explode('=', $value, 2);
$args[] =
rawurlencode(rawurldecode($pair[0])) .
'=' .
rawurlencode(rawurldecode($pair[1]));
}
usort($args, 'strcmp');
return implode('&', $args);
}
}
比较 \Cake\Http\Client\Auth\Oauth::_normalizedParams()
通过在客户端实例的 type
选项中指定类名来使用它:
'type' => 'AppOAuth',
ps
你的 $search
数组中不应该是 filter_groups
而不是 filterGroups
吗?
我正在尝试向本地 Magento2 rest API 发送 GET 请求以在特定时间后获取所有订单。我正在关注 http://devdocs.magento.com/guides/v2.1/howdoi/webapi/search-criteria.html#simple-search-using-a-timestamp. I'm using CakePHP 3.4's Http Client (https://book.cakephp.org/3.0/en/core-libraries/httpclient.html),并且已经使用 Oauth1 成功地与 Magento 集成,并且对 http://www.magento.dev.com/rest/V1/stockItems/:productSku
等更简单的 GET 请求没有任何问题。通过搜索条件是一个问题。响应始终是 401 Invalid Signature
.
使用 Postman,我可以获得对 http://www.magento.dev.com/rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=created_at&searchCriteria[filter_groups][0][filters][0][value]=2016-07-01 00:00:00&searchCriteria[filter_groups][0][filters][0][condition_type]=gt
这就是我所拥有的 far/how 我正在发送请求:
在Model/Table/OrdersTable.php:
public function importNewOrders(\App\Model\Entity\OauthIntegration $integrationDetails)
{
$this->OauthIntegrations = TableRegistry::get('OauthIntegrations');
$this->Orders = TableRegistry::get('Orders');
$timeCutOff = '2015-01-01 00:00:00';
$search = [
'searchCriteria' => [
'filterGroups' => [
0 => [
'filters' => [
0 => [
'field' => 'created_at',
'value' => $timeCutOff,
'condition_type' => 'gt'
]
]
]
]
]
];
// 'searchCriteria[filter_groups][0][filters][0][field]' => 'created_at',
// 'searchCriteria[filter_groups][0][filters][0][value]' => $timeCutOff,
// 'searchCriteria[filter_groups][0][filters][0][condition_type]' => 'gt'
$action = '/V1/orders';
$type = "GET";
$response = $this->OauthIntegrations->sendRequest(
$integrationDetails,
$action,
$type,
'',
$search);
Log::write('debug', $response->body());
return $response;
}
并在 Model\Table\OauthIntegrationsTable.php:
public function sendRequest(\App\Model\Entity\OauthIntegration $integrationDetails,
string $action, string $method = "GET", string $data = '', array $search = null)
{
$http = new Client([
'auth' => [
'type' => 'oauth',
'consumerKey' => $integrationDetails->oauth_consumer_key,
'consumerSecret' => $integrationDetails->oauth_consumer_secret,
'token' => $integrationDetails->oauth_token,
'tokenSecret' => $integrationDetails->oauth_token_secret
]
]);
$url = $integrationDetails->store_base_url . 'rest' . $action;
if ($method == 'GET'){
if (!isset($search)){
$search = [];
}
$response = $http->get($url, $search, []);
} else if ($method == 'POST'){
$response = $http->post($url, $data, [
'type' => 'json',
]);
} else if($method == 'PUT'){
$response = $http->put($url, $data, [
'type' => 'json',
]);
}
Log::write('debug', 'url: ' . $url . ' and status code: ' . $response->getStatusCode());
return $response;
}
这是错误(我希望)是无效签名响应的原因:
2017-03-28 10:07:01 Notice: Notice (8): Array to string conversion in [/var/www/cakephp/html/beacon/vendor/cakephp/cakephp/src/Http/Client/Auth/Oauth.php, line 315]
Trace:
Cake\Error\BaseErrorHandler::handleError() - CORE/src/Error/BaseErrorHandler.php, line 153
Cake\Http\Client\Auth\Oauth::_normalizedParams() - CORE/src/Http/Client/Auth/Oauth.php, line 315
Cake\Http\Client\Auth\Oauth::baseString() - CORE/src/Http/Client/Auth/Oauth.php, line 246
Cake\Http\Client\Auth\Oauth::_hmacSha1() - CORE/src/Http/Client/Auth/Oauth.php, line 143
Cake\Http\Client\Auth\Oauth::authentication() - CORE/src/Http/Client/Auth/Oauth.php, line 61
Cake\Http\Client::_addAuthentication() - CORE/src/Http/Client.php, line 501
Cake\Http\Client::_createRequest() - CORE/src/Http/Client.php, line 448
Cake\Http\Client::_doRequest() - CORE/src/Http/Client.php, line 341
Cake\Http\Client::get() - CORE/src/Http/Client.php, line 211
App\Model\Table\OauthIntegrationsTable::sendRequest() - APP/Model/Table/OauthIntegrationsTable.php, line 134
App\Model\Table\OrdersTable::importNewOrders() - APP/Model/Table/OrdersTable.php, line 672
App\Shell\MagentoShell::main() - APP/Shell/MagentoShell.php, line 36
Cake\Console\Shell::runCommand() - CORE/src/Console/Shell.php, line 472
Cake\Console\ShellDispatcher::_dispatch() - CORE/src/Console/ShellDispatcher.php, line 227
Cake\Console\ShellDispatcher::dispatch() - CORE/src/Console/ShellDispatcher.php, line 182
Cake\Console\ShellDispatcher::run() - CORE/src/Console/ShellDispatcher.php, line 128
[main] - ROOT/bin/cake.php, line 33
来自 Http\Client\Oauth.php 的代码发生错误的地方:
$pairs = [];
foreach ($args as $k => $val) {
if (is_array($val)) {
sort($val, SORT_STRING);
Log::write('debug', 'about to go through foreach($val as $nestedVal)');
foreach ($val as $nestedVal) {
Log::write('debug', $nestedVal);
$pairs[] = "$k=$nestedVal"; // <<< HERE
}
} else {
$pairs[] = "$k=$val";
}
}
从上面调试结果:
2017-03-28 10:07:01 Debug: about to go through foreach($val as $nestedVal)
2017-03-28 10:07:01 Debug: Array
(
[0] => Array
(
[filters] => Array
(
[0] => Array
(
[field] => created_at
[value] => 2015-01-01 00:00:00
[condition_type] => gt
)
)
)
)
综上所述,是否可以使用Cake的Http Client将多维数组传递给get请求中的第二个参数?
// Is it possible to replace ['q' => 'widget'] with a multi-dimensional array??
$response = $http->get('http://example.com/search', ['q' => 'widget']);
如果没有,使用 Cake 的 Http 客户端发送 GET 请求的最佳方式是什么:http://www.magento.dev.com/rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=created_at&searchCriteria[filter_groups][0][filters][0][value]=2016-07-01 00:00:00&searchCriteria[filter_groups][0][filters][0][condition_type]=gt
?
提前致谢!!!
可能存在错误
这可能被认为是一个错误。我认为 the OAuth specs 不会考虑 URL 中的这种 PHP 样式括号内容,因此 sorting/encoding 参数仅限于平面 key=value
集,即一个键是
searchCriteria[filter_groups][0][filters][0][field]
并且值为
created_at
然而,CakePHP OAuth 适配器将请求查询字符串解析为可能深度嵌套的数组结构,这将失败,因为它不处理这种情况。
我建议你 report this as a possible bug。进一步的问题可能会发生,因为编码似乎是在排序之前应用的,在 CakePHP 实现中,additonal 参数编码在排序之后应用(实际上可能没问题不过,我不确定)。
尝试使用自定义 OAuth 适配器作为解决方法
在此之前 fixed/enhanced,您可以使用自定义 OAuth 适配器来“正确”处理事情(无论在此上下文中意味着什么)。这是一个简单粗暴的例子(适用于我的 Magento API)。
创建src/Http/Client/Auth/AppOAuth.php
<?php
namespace App\Http\Client\Auth;
use Cake\Http\Client\Auth\Oauth;
class AppOAuth extends Oauth
{
protected function _normalizedParams($request, $oauthValues)
{
$query = parse_url($request->url(), PHP_URL_QUERY);
parse_str($query, $queryArgs);
$post = [];
$body = $request->body();
if (is_string($body) &&
$request->getHeaderLine('content-type') === 'application/x-www-form-urlencoded'
) {
parse_str($body, $post);
}
if (is_array($body)) {
$post = $body;
}
$args = array_merge($queryArgs, $oauthValues, $post);
$query = http_build_query($args);
$args = [];
foreach (explode('&', $query) as $value) {
$pair = explode('=', $value, 2);
$args[] =
rawurlencode(rawurldecode($pair[0])) .
'=' .
rawurlencode(rawurldecode($pair[1]));
}
usort($args, 'strcmp');
return implode('&', $args);
}
}
比较 \Cake\Http\Client\Auth\Oauth::_normalizedParams()
通过在客户端实例的 type
选项中指定类名来使用它:
'type' => 'AppOAuth',
ps
你的 $search
数组中不应该是 filter_groups
而不是 filterGroups
吗?