PluginProbe
Datafeedr API / 1.4.3
Datafeedr API v1.4.3
1.4.3 1.4.2 1.0.125 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.3 1.0.30 1.0.31 1.0.32 All 182 releases
← All changes | libraries/datafeedr.php +1911 -949 1.0.31 → 1.4.3 View file →
@@ -1,1146 +1,2108 @@
1 1 <?php
2 2
3 3 /**
4 - * Datafeedr Api Client Library.
4 + * Datafeedr API PHP Library
5 5 *
6 - * @version 0.1b.7382
7 - * @copyright Datafeedr 2007 ~ 2014 - All Rights Reserved
6 + * @version 3.0.0
8 7 *
9 - * @mainpage
8 + * Copyright (c) 2007 ~ 2017, Datafeedr - All Rights Reserved
10 9 *
11 - * Example of use:
10 + * Permission to use, copy, modify, and/or distribute this software for any
11 + * purpose with or without fee is hereby granted, provided that the above
12 + * copyright notice and this permission notice appear in all copies.
12 13 *
13 - * @code
14 - * $api = new DatafeedrApi('<access id>', '<secret key>');
14 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 + */
22 +
23 +/**
24 + * Class DatafeedrApi
15 25 *
16 - * foreach($api->getMerchants() as $merchant)
17 - * print $merchant['name'];
18 - *
19 - * $search = $api->searchRequest();
20 - * $search->addFilter("name LIKE shoe");
21 - * $search->addFilter("price < 100");
22 - * $search->addSort("price", DatafeedrApi::SORT_ASCENDING);
23 - * $search->setLimit(25);
24 - *
25 - * $products = $search->execute();
26 - *
27 - * foreach($products as $product)
28 - * print $product['name'];
29 - *
30 - * @endcode
31 - *
32 - *
33 - *
34 - **/
26 + * This is the core Datafeedr API class.
27 + */
28 +class DatafeedrApi {
35 29
36 -if(!class_exists('DatafeedrApi', false)) {
30 + protected $_accessId;
31 + protected $_secretKey;
37 32
33 + protected $_hasZlib;
34 + protected $_host;
35 + protected $_retry;
36 + protected $_retryTimeout;
37 + protected $_returnObjects;
38 + protected $_timeout;
39 + protected $_transport;
40 + protected $_https;
41 + protected $_url;
42 + protected $_userAgent;
43 + protected $_domain;
44 +
45 + protected $_status;
46 + protected $_errors;
47 +
48 + const SORT_DESCENDING = - 1;
49 + const SORT_ASCENDING = + 1;
50 +
51 + const DEFAULT_HOST = 'api.datafeedr.com';
52 +
53 + const REQUEST_COMPRESSION_THRESHOLD = 1024;
54 +
55 + const VERSION = '3.0.0';
56 +
38 57 /**
39 - * Datafeedr API core class.
40 - **/
41 - class DatafeedrApi
42 - {
43 - protected $_accessId;
44 - protected $_secretKey;
58 + * DatafeedrApi constructor.
59 + *
60 + * @since 1.0.0
61 + *
62 + * @param string $secretKey Datafeedr API Secret Key.
63 + * @param array $options Options.
64 + *
65 + * Possble options:
66 + *
67 + * - host: API host name. Default: 'api.datafeedr.com'
68 + * - https: TRUE if using https. Default: FALSE.
69 + * - transport: HTTP transport name or function. Default: 'wordpress'
70 + * - timeout: HTTP connection timeout, in seconds. Default: 0
71 + * - returnObjects: True to return Objects. False to return associative arrays Default: false
72 + * - retry: How many times to repeat a request on a temporary failure. Default: 0 (do not repeat)
73 + * - retryTimeout: Timeout between retry requests, in seconds. Default: 5
74 + *
75 + * The `transport` option tells how HTTP requests should be made.
76 + * It can be either a string that describes one of built-in transports ("curl", "file" or "wordpress"),
77 + * or a callable object that should accept a URL, an array of headers and a string of post data and
78 + * should return an array [int http response status, string response body].
79 + *
80 + *
81 + * @param string $accessId Datafeedr API Access ID.
82 + *
83 + * @throws DatafeedrError Throws error if any option is invalid.
84 + */
85 + public function __construct( $accessId, $secretKey, $options = null ) {
45 86
46 - protected $_transport;
47 - protected $_timeout;
48 - protected $_url;
49 - protected $_returnObjects;
87 + $this->_accessId = $accessId;
88 + $this->_secretKey = $secretKey;
50 89
51 - protected $_status;
90 + $this->_errors = array(
91 + 1 => 'DatafeedrBadRequestError',
92 + 2 => 'DatafeedrAuthenticationError',
93 + 3 => 'DatafeedrLimitExceededError',
94 + 4 => 'DatafeedrQueryError',
95 + 7 => 'DatafeedrExternalError',
96 + 9 => 'DatafeedrServerError',
97 + );
52 98
53 - const SORT_DESCENDING = -1;
54 - const SORT_ASCENDING = +1;
99 + $this->_parseOptions( $options );
100 + }
55 101
56 - const DEFAULT_URL = 'http://api.datafeedr.com';
57 - const DEFAULT_TIMEOUT = 30;
102 + /**
103 + * Returns API status information.
104 + *
105 + * @since 1.0.0
106 + *
107 + * @return array An array of API Status information.
108 + */
109 + public function getStatus() {
110 + $this->apiCall( 'status' );
58 111
59 - const VERSION = '0.1b.7382';
112 + return $this->_status;
113 + }
60 114
61 - /**
62 - * Constructor.
63 - *
64 - * @param string $accessId Access ID.
65 - * @param object $secretKey Secret key.
66 - * @param string|callable $transport (optional) HTTP transport function.
67 - * @param int $timeout (optional) HTTP connection timeout, in seconds.
68 - * @param bool $returnObjects (optional) if TRUE, responses are objects, otherwise associative arrays.
69 - *
70 - * The optional $transport parameter tells how HTTP requests should be made.
71 - * It can be either a string that describes one of built-in transports ("curl", "file" or "socket"),
72 - * or a callable object that should accept an url, an array of headers and a string of post data and
73 - * should return an array [int http response status, string response body].
74 - *
75 - **/
76 - public function __construct($accessId, $secretKey, $transport = 'curl', $timeout = 0, $returnObjects = FALSE) {
77 - $this->_accessId = $accessId;
78 - $this->_secretKey = $secretKey;
115 + /**
116 + * Return status information from the last request.
117 + *
118 + * If no API request has been made, return NULL
119 + *
120 + * @since 1.0.0
121 + *
122 + * @return array|null Status information or NULL.
123 + */
124 + public function lastStatus() {
125 + return $this->_status;
126 + }
79 127
80 - $this->_errors = array(
81 - 1 => 'DatafeedrBadRequestError',
82 - 2 => 'DatafeedrAuthenticationError',
83 - 3 => 'DatafeedrLimitExceededError',
84 - 4 => 'DatafeedrQueryError',
85 - 7 => 'DatafeedrExternalError',
86 - 9 => 'DatafeedrServerError',
87 - );
128 + /**
129 + * Return the list of networks.
130 + *
131 + * @since 1.0.0
132 + *
133 + * @param boolean $includeEmpty Optional. If FALSE, omit networks with 0 products.
134 + * @param array $fields Optional. An array of fields to retrieve.
135 + *
136 + * @param integer|array $networkId Optional. Network ID or an array of network IDs.
137 + *
138 + * @return array An array of Networks.
139 + */
140 + public function getNetworks( $networkId = null, $includeEmpty = false, $fields = null ) {
88 141
89 - $this->_url = self::DEFAULT_URL;
90 - $this->_timeout = $timeout ? $timeout : self::DEFAULT_TIMEOUT;
91 - $this->_returnObjects = $returnObjects;
142 + $request = array();
92 143
93 - switch($transport) {
94 - case 'curl':
95 - $this->_transport = array($this, '_transportCurl');
96 - break;
97 - case 'file':
98 - $this->_transport = array($this, '_transportFile');
99 - break;
100 - case 'socket':
101 - $this->_transport = array($this, '_transportSocket');
102 - break;
103 - default:
104 - if(!is_callable($transport)) {
105 - throw new DatafeedrError("Transport must be a function");
106 - }
107 - $this->_transport = $transport;
108 - }
144 + if ( $networkId ) {
145 + $request['_ids'] = $this->_intarray( $networkId );
109 146 }
110 147
111 - /**
112 - * Return status information.
113 - *
114 - * @return array
115 - *
116 - **/
117 - public function getStatus() {
118 - $this->apiCall('status');
119 - return $this->_status;
148 + $request['skip_empty'] = intval( ! $includeEmpty );
149 +
150 + if ( $fields ) {
151 + $request['fields'] = $fields;
120 152 }
121 153
122 - /**
123 - * Return status information from the last request.
124 - *
125 - * If no Api request have been made, return NULL
126 - *
127 - * @return array|null
128 - *
129 - **/
130 - public function lastStatus() {
131 - return $this->_status;
154 + $response = $this->apiCall( 'networks', $request );
155 +
156 + return $this->_get( $response, 'networks' );
157 + }
158 +
159 + /**
160 + * Return the list of merchants.
161 + *
162 + * @since 1.0.0
163 + *
164 + * @param bool $includeEmpty Optional. If FALSE, omit merchants with 0 products.
165 + * @param array $fields Optional. An array of fields to retrieve.
166 + *
167 + * @param integer|array $networkId Optional. Network ID or array of Network IDs.
168 + *
169 + * @return array An array of merchants.
170 + */
171 + public function getMerchants( $networkId = null, $includeEmpty = false, $fields = null ) {
172 +
173 + $request = array();
174 +
175 + if ( $networkId ) {
176 + $request['source_ids'] = $this->_intarray( $networkId );
132 177 }
133 178
134 - /**
135 - * Return the list of networks.
136 - *
137 - * @param int|array $networkId (optional) Network id or an array of network ids
138 - * @param bool $includeEmpty (optional) If FALSE, omit networks with 0 products
139 - * @param array $fields (optional) list of fields to retrieve
140 - * @return array
141 - *
142 - **/
143 - public function getNetworks($networkId = NULL, $includeEmpty = FALSE, $fields = NULL) {
144 - $request = array();
145 - if($networkId) {
146 - $request['_ids'] = $this->_intarray($networkId);
147 - }
148 - $request['skip_empty'] = intval(!$includeEmpty);
149 - if($fields) {
150 - $request['fields'] = $fields;
151 - }
152 - $response = $this->apiCall('networks', $request);
153 - return $this->_get($response, 'networks');
179 + $request['skip_empty'] = intval( ! $includeEmpty );
180 +
181 + if ( $fields ) {
182 + $request['fields'] = $fields;
154 183 }
155 184
156 - /**
157 - * Return the list of merchants.
158 - *
159 - * @param int|array $networkId (optional) Network id or array of network ids
160 - * @param bool $includeEmpty (optional) If FALSE, omit merchants with 0 products
161 - * @param array $fields (optional) list of fields to retrieve
162 - * @return array
163 - *
164 - **/
165 - public function getMerchants($networkId = NULL, $includeEmpty = FALSE, $fields = NULL) {
166 - $request = array();
167 - if($networkId) {
168 - $request['source_ids'] = $this->_intarray($networkId);
169 - }
170 - $request['skip_empty'] = intval(!$includeEmpty);
171 - if($fields) {
172 - $request['fields'] = $fields;
173 - }
174 - $response = $this->apiCall('merchants', $request);
175 - return $this->_get($response, 'merchants');
185 + $response = $this->apiCall( 'merchants', $request );
186 +
187 + return $this->_get( $response, 'merchants' );
188 + }
189 +
190 + /**
191 + * Return a list of merchants by their IDs.
192 + *
193 + * @since 1.0.0
194 + *
195 + * @param boolean $includeEmpty Optional. If FALSE, omit merchants with 0 products.
196 + * @param array $fields Optional. An array of fields to retrieve.
197 + *
198 + * @param integer|array $merchantId Merchant ID or array of Merchant IDs.
199 + *
200 + * @return array An array of merchants.
201 + */
202 + public function getMerchantsById( $merchantId, $includeEmpty = false, $fields = null ) {
203 +
204 + $request = array();
205 + $request['_ids'] = $this->_intarray( $merchantId );
206 + $request['skip_empty'] = intval( ! $includeEmpty );
207 +
208 + if ( $fields ) {
209 + $request['fields'] = $fields;
176 210 }
177 211
178 - /**
179 - * Return the list of merchants by their ids.
180 - *
181 - * @param int|array $merchantId Merchant id or array of network ids
182 - * @param bool $includeEmpty (optional) If FALSE, omit merchants with 0 products
183 - * @param array $fields (optional) list of fields to retrieve
184 - * @return array
185 - *
186 - **/
187 - public function getMerchantsById($merchantId, $includeEmpty = FALSE, $fields = NULL) {
188 - $request = array();
189 - $request['_ids'] = $this->_intarray($merchantId);
190 - $request['skip_empty'] = intval(!$includeEmpty);
191 - if($fields) {
192 - $request['fields'] = $fields;
193 - }
194 - $response = $this->apiCall('merchants', $request);
195 - return $this->_get($response, 'merchants');
212 + $response = $this->apiCall( 'merchants', $request );
213 +
214 + return $this->_get( $response, 'merchants' );
215 + }
216 +
217 + /**
218 + * Return a list of searchable fields.
219 + *
220 + * @since 1.0.0
221 + *
222 + * @param integer|array $networkId Optional. Network ID or array of network IDs.
223 + *
224 + * @return array An array of searchable fields.
225 + * @todo - Does this return a list of all fields for a specific network or only indexed/searchable fields? Update docs accordingly.
226 + *
227 + */
228 + public function getFields( $networkId = null ) {
229 +
230 + $request = array();
231 +
232 + if ( $networkId ) {
233 + $request['source_ids'] = $this->_intarray( $networkId );
196 234 }
197 235
198 - /**
199 - * Return the list of searchable fields.
200 - *
201 - * @param int|array $networkId (optional) Network id or array of network ids
202 - * @return array
203 - *
204 - **/
205 - public function getFields($networkId = NULL) {
206 - $request = array();
207 - if($networkId) {
208 - $request['source_ids'] = $this->_intarray($networkId);
209 - }
210 - $response = $this->apiCall('fields', $request);
211 - return $this->_get($response, 'fields');
236 + $response = $this->apiCall( 'fields', $request );
237 +
238 + return $this->_get( $response, 'fields' );
239 + }
240 +
241 + /**
242 + * Return a list of products by their IDs.
243 + *
244 + * @since 1.0.0
245 + *
246 + * @param array $fields Optional. An array of fields to retrieve.
247 + *
248 + * @param integer|array $productId Product ID or an array of products IDs.
249 + *
250 + * @return array An array of Products.
251 + */
252 + public function getProducts( $productId, $fields = null ) {
253 +
254 + $request = array();
255 + $request['_ids'] = $this->_intarray( $productId );
256 + $request['string_ids'] = 1;
257 +
258 + if ( $fields ) {
259 + $request['fields'] = $fields;
212 260 }
213 261
214 - /**
215 - * Return the list of products by their ids.
216 - *
217 - * @param int|array $productId Product id or an array of products ids.
218 - * @param array $fields (optional) list of fields to retrieve.
219 - * @return array
220 - *
221 - **/
222 - public function getProducts($productId, $fields = NULL) {
262 + $response = $this->apiCall( 'get', $request );
263 +
264 + return $this->_get( $response, 'products' );
265 + }
266 +
267 + /**
268 + * Return a list of Zanox merchant IDs ("zmids").
269 + *
270 + * @since 1.0.0
271 + *
272 + * @param integer $adspaceId Zanox Adspace ID.
273 + * @param string $connectId Zanox Connection ID.
274 + *
275 + * @param integer|array $merchantId Merchant ID or an array of merchant IDs.
276 + *
277 + * @return array An array of arrays (adspace_id, merchant_id, program_id, zmid).
278 + */
279 + public function getZanoxMerchantIds( $merchantId, $adspaceId, $connectId ) {
280 +
281 + $request = array();
282 +
283 + $request['merchant_ids'] = $this->_intarray( $merchantId );
284 + $request['adspace_id'] = $adspaceId;
285 + $request['connect_id'] = $connectId;
286 +
287 + $response = $this->apiCall( 'zanox_merchant_ids', $request );
288 +
289 + return $this->_get( $response, 'zanox_merchant_ids' );
290 + }
291 +
292 + /**
293 + * Return a list of PerformanceHorizon campaign references ("camrefs").
294 + *
295 + * @since 2.0.0
296 + *
297 + * @param string $applicationKey PerformanceHorizon application_key.
298 + * @param string $userApiKey PerformanceHorizon user_api_key.
299 + * @param string $publisherId PerformanceHorizon publisher_id.
300 + *
301 + * @param integer|array $merchantId Merchant ID or an array of merchant IDs.
302 + *
303 + * @return array An array of arrays (campaign_id, camref, merchant_id).
304 + */
305 +
306 + public function getPerformanceHorizonCamrefs( $merchantId, $applicationKey, $userApiKey, $publisherId ) {
307 +
308 + $request = array();
309 +
310 + $request['merchant_ids'] = $this->_intarray( $merchantId );
311 + $request['application_key'] = $applicationKey;
312 + $request['user_api_key'] = $userApiKey;
313 + $request['publisher_id'] = $publisherId;
314 +
315 + $response = $this->apiCall( 'performancehorizon_camrefs', $request );
316 +
317 + return $this->_get( $response, 'performancehorizon_camrefs' );
318 + }
319 +
320 + /**
321 + * Return a list of Effiliation affiliate ids.
322 + *
323 + * @since 2.0.2
324 + *
325 + * @param string $apiKey Effiliation api_key.
326 + *
327 + * @param integer|array $merchantId Merchant ID or an array of merchant IDs.
328 + *
329 + * @return array An array of arrays (affiliate_id, merchant_id).
330 + */
331 +
332 + public function getEffiliationAffiliateIds( $merchantId, $apiKey ) {
333 +
334 + $request = array();
335 +
336 + $request['merchant_ids'] = $this->_intarray( $merchantId );
337 + $request['api_key'] = $apiKey;
338 +
339 + $response = $this->apiCall( 'effiliation_affiliate_ids', $request );
340 +
341 + return $this->_get( $response, 'effiliation_affiliate_ids' );
342 + }
343 +
344 + /**
345 + * Create a new DatafeedrSearchRequest object.
346 + *
347 + * @since 1.0.0
348 + *
349 + * @return DatafeedrSearchRequest
350 + */
351 + public function searchRequest() {
352 + return new DatafeedrSearchRequest( $this );
353 + }
354 +
355 + /**
356 + * Create a new DatafeedrMerchantSearchRequest object.
357 + *
358 + * @since 1.0.0
359 + *
360 + * @return DatafeedrMerchantSearchRequest
361 + */
362 + public function merchantSearchRequest() {
363 + return new DatafeedrMerchantSearchRequest( $this );
364 + }
365 +
366 + /**
367 + * Create a new DatafeedrAmazonSearchRequest object.
368 + *
369 + * @since 1.0.0
370 + *
371 + * @param string $awsSecretKey Amazon Secret Key.
372 + * @param string $awsAssociateTag Amazon Associates tag.
373 + * @param string $locale The country locale code.
374 + *
375 + * @param string $awsAccessKeyId Amazon Access Key.
376 + *
377 + * @return DatafeedrAmazonSearchRequest
378 + */
379 + public function amazonSearchRequest( $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale = 'US' ) {
380 + return new DatafeedrAmazonSearchRequest( $this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale );
381 + }
382 +
383 + /**
384 + * Create a new DatafeedrAmazonLookupRequest object.
385 + *
386 + * @since 1.0.0
387 + *
388 + * @param string $awsSecretKey Amazon Secret Key.
389 + * @param string $awsAssociateTag Amazon Associates tag.
390 + * @param string $locale The country locale code.
391 + *
392 + * @param string $awsAccessKeyId Amazon Access Key.
393 + *
394 + * @return DatafeedrAmazonLookupRequest
395 + */
396 + public function amazonLookupRequest( $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale = 'US' ) {
397 + return new DatafeedrAmazonLookupRequest( $this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale );
398 + }
399 +
400 + /** CreatorAPI */
401 + public function amazonCreatorApiSearchRequest( $capiMarketplace = 'US' ) {
402 + return new DatafeedrAmazonCreatorApiSearchRequest( $this, $capiMarketplace = 'US' );
403 + }
404 +
405 + /** CreatorAPI */
406 +// public function amazonCreatorApiLookupRequest( $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale = 'US' ) {
407 +// return new DatafeedrAmazonCreatorApiLookupRequest( $this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale );
408 +// }
409 +
410 + /**
411 + * Perform the raw API call.
412 + *
413 + * @since 1.0.0
414 + *
415 + * @param array $request Optional. Request data.
416 + *
417 + * @param string $action API Action. (Examples: status, merchants, networks, search, etc...)
418 + *
419 + * @return array Returns $response array.
420 + * @throws DatafeedrHTTPError Throws error if request status is not 200.
421 + *
422 + */
423 + public function apiCall( $action, $request = null ) {
424 +
425 + if ( ! $request ) {
223 426 $request = array();
224 - $request['_ids'] = $this->_intarray($productId);
225 - $request['string_ids'] = 1;
226 - if($fields) {
227 - $request['fields'] = $fields;
228 - }
229 - $response = $this->apiCall('get', $request);
230 - return $this->_get($response, 'products');
231 427 }
232 428
233 - /**
234 - * Return the list of Zanox merchant ids ("zmids").
235 - *
236 - * @param int|array $merchantId Merchant id or an array of merchant ids.
237 - * @param int $adspaceId Zanox adspace Id.
238 - * @param string $connectId Zanox connection Id.
239 - * @return array
240 - *
241 - **/
242 - public function getZanoxMerchantIds($merchantId, $adspaceId, $connectId) {
243 - $request = array();
244 - $request['merchant_ids'] = $this->_intarray($merchantId);
245 - $request['adspace_id'] = $adspaceId;
246 - $request['connect_id'] = $connectId;
247 - $response = $this->apiCall('zanox_merchant_ids', $request);
248 - return $this->_get($response, 'zanox_merchant_ids');
429 + $request['aid'] = $this->_accessId;
430 + $request['timestamp'] = gmdate( 'Y-m-d H:i:s' );
431 + $request['domain'] = $this->_domain;
432 +
433 + if ( $this->_https ) {
434 + $request['akey'] = $this->_secretKey;
435 + } else {
436 + $message = $request['aid'] . $action . $request['timestamp'];
437 + $request['signature'] = hash_hmac( 'sha256', $message, $this->_secretKey, false );
249 438 }
250 439
251 - /**
252 - * Create a new DatafeedrSearchRequest object.
253 - *
254 - * @return DatafeedrSearchRequest
255 - *
256 - **/
257 - public function searchRequest() {
258 - return new DatafeedrSearchRequest($this);
440 + $postdata = json_encode( $request );
441 + $url = $this->_url . '/' . $action;
442 + $headers = array(
443 + 'Host: ' . $this->_host,
444 + 'Content-Type: application/json',
445 + 'Accept: application/json',
446 + 'Connection: close',
447 + 'User-Agent: ' . $this->_userAgent
448 + );
449 +
450 + if ( $this->_hasZlib && strlen( $postdata ) >= self::REQUEST_COMPRESSION_THRESHOLD ) {
451 + $postdata = gzcompress( $postdata );
452 + $headers [] = 'Content-Encoding: deflate';
259 453 }
260 454
261 - /**
262 - * Create a new DatafeedrMerchantSearchRequest object.
263 - *
264 - * @return DatafeedrMerchantSearchRequest
265 - *
266 - **/
267 - public function merchantSearchRequest() {
268 - return new DatafeedrMerchantSearchRequest($this);
455 + $headers [] = 'Content-Length: ' . strlen( $postdata );
456 +
457 + list( $status, $response ) = $this->_performRequest( $url, $headers, $postdata );
458 +
459 + if ( strlen( $response ) ) {
460 + $response = json_decode( $response, ! $this->_returnObjects );
269 461 }
270 462
271 - /**
272 - * Create a new DatafeedrAmazonSearchRequest object.
273 - *
274 - * @return DatafeedrAmazonSearchRequest
275 - *
276 - **/
277 - public function amazonSearchRequest($awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
278 - return new DatafeedrAmazonSearchRequest($this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale);
463 + $error = $this->_get( $response, 'error' );
464 + if ( $error ) {
465 + $type = $this->_get( $response, 'type' );
466 + $cls = isset( $this->_errors[ $type ] ) ? $this->_errors[ $type ] : 'DatafeedrError';
467 + throw new $cls( $this->_get( $response, 'message' ), $error );
279 468 }
280 469
281 - /**
282 - * Create a new DatafeedrAmazonLookupRequest object.
283 - *
284 - * @return DatafeedrAmazonLookupRequest
285 - *
286 - **/
287 - public function amazonLookupRequest($awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
288 - return new DatafeedrAmazonLookupRequest($this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale);
470 + if ( 200 != $status ) {
471 + throw new DatafeedrHTTPError( "Status $status" );
289 472 }
290 473
291 - /**
292 - * Perform the raw Api call.
293 - *
294 - * @param string $action Api action.
295 - * @param array $request (optional) Request data.
296 - *
297 - * @return array
298 - *
299 - **/
300 - public function apiCall($action, $request = NULL) {
301 - if(!$request) {
302 - $request = array();
303 - }
474 + $this->_status = $this->_get( $response, 'status' );
304 475
305 - $request['aid'] = $this->_accessId;
306 - $request['timestamp'] = gmdate('Y-m-d H:i:s');
476 + return $response;
477 + }
307 478
308 - $message = $request['aid'] .$action . $request['timestamp'];
309 - $request['signature'] = hash_hmac('sha256', $message, $this->_secretKey, FALSE);
479 + /**
480 + * Returns the default set of options.
481 + *
482 + * @since 2.0.0
483 + *
484 + * @returns array $options.
485 + *
486 + */
487 + protected function _defaultOptions() {
488 + return array(
489 + 'host' => self::DEFAULT_HOST,
490 + 'https' => false,
491 + 'transport' => 'wordpress_or_curl',
492 + 'timeout' => 30,
493 + 'returnObjects' => false,
494 + 'retry' => 0,
495 + 'retryTimeout' => 5,
496 + 'domain' => '',
497 + );
498 + }
310 499
311 - $postdata = json_encode($request);
312 - $url = $this->_url . '/' . $action;
313 - $headers = array(
314 - 'Content-Type: application/json',
315 - 'Accept: application/json',
316 - 'Content-Length: '. strlen($postdata),
317 - 'Connection: close',
318 - 'User-Agent: datafeedr.php.' . self::VERSION
319 - );
320 - list($status, $response) = call_user_func($this->_transport, $url, $headers, $postdata);
321 - if(strlen($response)) {
322 - $response = json_decode($response, !$this->_returnObjects);
500 + /**
501 + * Parse constructor options.
502 + *
503 + * @since 2.0.0
504 + *
505 + * @param array $options .
506 + *
507 + * @throws DatafeedrError Throws error if any option is invalid.
508 + */
509 + protected function _parseOptions( $options ) {
510 + $opts = $this->_defaultOptions();
511 +
512 + if ( ! is_null( $options ) ) {
513 + if ( ! is_array( $options ) ) {
514 + throw new DatafeedrError( "Options must be an array" );
323 515 }
324 516
325 - $error = $this->_get($response, 'error');
326 - if($error) {
327 - $type = $this->_get($response, 'type');
328 - $cls = isset($this->_errors[$type]) ? $this->_errors[$type] : 'DatafeedrError';
329 - throw new $cls($this->_get($response, 'message'), $error);
517 + foreach ( $options as $key => $value ) {
518 + if ( isset( $opts[ $key ] ) ) {
519 + $opts[ $key ] = $value;
520 + }
330 521 }
522 + }
331 523
332 - if($status != 200) {
333 - throw new DatafeedrHTTPError("Status $status");
524 + $pt = $opts['https'] ? 'https' : 'http';
525 + $tr = $opts['transport'];
526 +
527 + $this->_url = $pt . '://' . $opts['host'];
528 + $this->_https = $opts['https'];
529 + $this->_host = $opts['host'];
530 + $this->_timeout = (int) $opts['timeout'];
531 + $this->_returnObjects = (int) $opts['returnObjects'];
532 + $this->_retry = (int) $opts['retry'];
533 + $this->_retryTimeout = (int) $opts['retryTimeout'];
534 + $this->_domain = (string) $opts['domain'];
535 +
536 + switch ( $tr ) {
537 + case 'curl':
538 + $this->_transport = array( $this, '_transportCurl' );
539 + break;
540 + case 'file':
541 + $this->_transport = array( $this, '_transportFile' );
542 + break;
543 + case 'wordpress':
544 + if ( ! function_exists( 'wp_remote_post' ) ) {
545 + throw new DatafeedrError( "Wordpress transport requires wp_remote_post" );
546 + }
547 + $this->_transport = array( $this, '_transportWordpress' );
548 + break;
549 + case 'wordpress_or_curl':
550 + if ( ! function_exists( 'wp_remote_post' ) ) {
551 + $this->_transport = array( $this, '_transportCurl' );
552 + $tr = 'curl';
553 + } else {
554 + $this->_transport = array( $this, '_transportWordpress' );
555 + $tr = 'wordpress';
556 + }
557 + break;
558 +
559 + default:
560 + if ( ! is_callable( $tr ) ) {
561 + throw new DatafeedrError( "Transport must be a function" );
562 + }
563 + $this->_transport = $tr;
564 + $tr = 'custom';
565 + }
566 +
567 + $this->_hasZlib = function_exists( 'gzcompress' );
568 + $this->_userAgent = sprintf( 'datafeedr.php.%s/%s/zlib=%s', self::VERSION, $tr,
569 + $this->_hasZlib ? 'yes' : 'no' );
570 + }
571 +
572 + /**
573 + * Perform an HTTP request.
574 + *
575 + * @since 2.0.0
576 + *
577 + * @param array $headers
578 + * @param string $postdata
579 + *
580 + * @param string $url
581 + *
582 + * @return array An array of (status, responseBody)
583 + * @throws DatafeedrConnectionError
584 + *
585 + */
586 + protected function _performRequest( $url, $headers, $postdata ) {
587 + $retry = $this->_retry;
588 +
589 + while ( true ) {
590 + try {
591 + return call_user_func( $this->_transport, $url, $headers, $postdata );
592 + } catch ( DatafeedrConnectionError $err ) {
593 + if ( $retry <= 0 ) {
594 + throw $err;
595 + }
596 + sleep( $this->_retryTimeout );
597 + $retry --;
334 598 }
599 + }
335 600
336 - $this->_status = $this->_get($response, 'status');
337 - return $response;
601 + return array();
602 + }
603 +
604 + /**
605 + * Convert an ID or an array of IDs to a simple array of IDs.
606 + *
607 + * @since 1.0.0
608 + *
609 + * @param integer|string|array $id_or_ids An ID or an array of IDs.
610 + *
611 + * @return array An array of IDs.
612 + */
613 + protected function _intarray( $id_or_ids ) {
614 +
615 + if ( is_numeric( $id_or_ids ) ) {
616 + return array( $id_or_ids );
338 617 }
339 618
340 - protected function _intarray($id_or_ids) {
341 - if(is_numeric($id_or_ids)) {
342 - return array($id_or_ids);
343 - }
344 - if(is_array($id_or_ids)) {
345 - return array_values($id_or_ids);
346 - }
347 - return array();
619 + if ( is_array( $id_or_ids ) ) {
620 + return array_values( $id_or_ids );
348 621 }
349 622
350 - protected function _get($obj, $prop, $default=NULL) {
351 - if(is_array($obj) && isset($obj[$prop])) {
352 - return $obj[$prop];
353 - }
354 - if(is_object($obj) && isset($obj->$prop)) {
355 - return $obj->$prop;
356 - }
357 - return $default;
623 + return array();
624 + }
625 +
626 + /**
627 + * Returns a specific value from an array or object for a given key or property. If key or
628 + * property does not exist, returns $default.
629 + *
630 + * @since 1.0.0
631 + *
632 + * @param string $prop The array key or object property to get the value for.
633 + * @param null $default Optional. The value to return if $obj or $prop does not exist.
634 + *
635 + * @param array|object $obj An array or object to extract value from.
636 + *
637 + * @return mixed|null The returned value.
638 + */
639 + protected function _get( $obj, $prop, $default = null ) {
640 +
641 + if ( is_array( $obj ) && isset( $obj[ $prop ] ) ) {
642 + return $obj[ $prop ];
358 643 }
359 644
645 + if ( is_object( $obj ) && isset( $obj->$prop ) ) {
646 + return $obj->$prop;
647 + }
360 648
361 - /**
362 - * Perform a HTTP post request by the means of the curl library.
363 - *
364 - * @param string $url Request url.
365 - * @param array $headers Array of headers.
366 - * @param string $postdata Post data.
367 - * @return array (int http status, string response body)
368 - *
369 - **/
370 - protected function _transportCurl($url, $headers, $postdata) {
371 - $ch = curl_init();
372 - curl_setopt($ch, CURLOPT_URL, $url);
373 - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_timeout);
374 - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
375 - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
376 - curl_setopt($ch, CURLOPT_POST, 1);
377 - curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
649 + return $default;
650 + }
378 651
379 - $response = curl_exec($ch);
380 - $status = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
381 - $errno = curl_errno($ch);
382 - $errmsg = curl_error($ch);
652 + /**
653 + * Perform an HTTP POST request using the CURL library.
654 + *
655 + * @since 1.0.0
656 + *
657 + * @param array $headers Array of headers.
658 + * @param string $postdata Post data.
659 + *
660 + * @param string $url Request url.
661 + *
662 + * @return array (int http status, string response body)
663 + * @throws DatafeedrConnectionError Throws error if curl_errno() returns an error.
664 + *
665 + */
666 + protected function _transportCurl( $url, $headers, $postdata ) {
383 667
384 - curl_close($ch);
668 + $ch = curl_init();
669 + curl_setopt( $ch, CURLOPT_URL, $url );
670 + curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $this->_timeout );
671 + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
672 + curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
673 + curl_setopt( $ch, CURLOPT_POST, 1 );
674 + curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
675 + curl_setopt( $ch, CURLOPT_ENCODING, '' );
676 + $response = curl_exec( $ch );
677 + $status = intval( curl_getinfo( $ch, CURLINFO_HTTP_CODE ) );
678 + $errno = curl_errno( $ch );
679 + $errmsg = curl_error( $ch );
385 680
386 - if($errno) {
387 - throw new DatafeedrHTTPError($errmsg, $errno);
388 - }
681 + curl_close( $ch );
389 682
390 - return array($status, $response);
683 + if ( $errno ) {
684 + throw new DatafeedrConnectionError( $errmsg, $errno );
391 685 }
392 686
393 - /**
394 - * Perform a HTTP post request using file functions.
395 - *
396 - * @param string $url Request url.
397 - * @param array $headers Array of headers.
398 - * @param string $postdata Post data.
399 - * @return array (int http status, string response body)
400 - *
401 - **/
402 - protected function _transportFile($url, $headers, $postdata) {
403 - $options = array('http' => array(
404 - 'method' => 'POST',
405 - 'content' => $postdata,
406 - 'header' => implode("\r\n", $headers),
407 - 'ignore_errors' => TRUE,
408 - 'timeout' => $this->_timeout,
409 - ));
410 - $context = stream_context_create($options);
411 - $response = file_get_contents($url, false, $context);
687 + return array( $status, $response );
688 + }
412 689
413 - $status = 200;
414 - if(isset($http_response_header) && isset($http_response_header[0])) {
415 - if(preg_match('/HTTP.+?(\d\d\d)/', $http_response_header[0], $match)) {
416 - $status = intval($match[1]);
417 - }
418 - } else if($response === false) {
419 - throw new DatafeedrHTTPError("HTTP error: invalid response");
690 + /**
691 + * Perform a HTTP post request using file functions.
692 + *
693 + * @since 1.0.0
694 + *
695 + * @param array $headers Array of headers.
696 + * @param string $postdata Post data.
697 + *
698 + * @param string $url Request url.
699 + *
700 + * @return array (int http status, string response body)
701 + * @throws DatafeedrConnectionError Throws error if $response is false.
702 + *
703 + */
704 + protected function _transportFile( $url, $headers, $postdata ) {
705 +
706 + $options = array(
707 + 'http' => array(
708 + 'method' => 'POST',
709 + 'content' => $postdata,
710 + 'header' => implode( "\r\n", $headers ),
711 + 'ignore_errors' => true,
712 + 'timeout' => $this->_timeout,
713 + )
714 + );
715 + $context = stream_context_create( $options );
716 + $response = file_get_contents( $url, false, $context );
717 +
718 + $status = 200;
719 + if ( isset( $http_response_header ) && isset( $http_response_header[0] ) ) {
720 + if ( preg_match( '/HTTP.+?(\d\d\d)/', $http_response_header[0], $match ) ) {
721 + $status = intval( $match[1] );
420 722 }
421 - return array($status, $response);
723 + } else if ( $response === false ) {
724 + throw new DatafeedrConnectionError( "Invalid response" );
422 725 }
423 726
424 - /**
425 - * Perform a HTTP post request using sockets.
426 - *
427 - * @param string $url Request url.
428 - * @param array $headers Array of headers.
429 - * @param string $postdata Post data.
430 - * @return array (int http status, string response body)
431 - *
432 - **/
433 - protected function _transportSocket($url, $headers, $postdata) {
434 - $parts = parse_url($url);
435 - $errno = 0;
436 - $errmsg = '';
727 + return array( $status, $response );
728 + }
437 729
438 - $fp = fsockopen($parts['host'], 80, $errno, $errmsg, $this->_timeout);
439 - if(!$fp) {
440 - throw new DatafeedrHTTPError($errmsg, $errno);
441 - }
730 + /**
731 + * Perform a HTTP post request using Wordpress functions.
732 + *
733 + * @since 1.0.0
734 + *
735 + * @param array $headers Array of headers.
736 + * @param string $postdata Post data.
737 + *
738 + * @param string $url Request url.
739 + *
740 + * @return array (int http status, string response body)
741 + * @throws DatafeedrConnectionError Throws error if $response is WP_Error and the error code is 'http_request_failed'.
742 + * @throws DatafeedrHTTPError Throws error if $response is WP_Error.
743 + *
744 + */
745 + protected function _transportWordpress( $url, $headers, $postdata ) {
442 746
443 - fwrite($fp, "POST " . $parts['path'] . " HTTP/1.1\r\n");
444 - fwrite($fp, implode("\r\n", $headers) . "\r\n\r\n");
445 - fwrite($fp, $postdata);
747 + $ha = array();
748 + foreach ( $headers as $h ) {
749 + $h = explode( ':', $h, 2 );
750 + $ha[ strtolower( $h[0] ) ] = $h[1];
751 + }
446 752
447 - $buf = '';
448 - while(!feof($fp)) {
449 - $buf .= fgets($fp, 1024);
450 - }
451 - fclose($fp);
753 + $args = array(
754 + 'method' => 'POST',
755 + 'headers' => $ha,
756 + 'body' => $postdata,
757 + 'httpversion' => '1.1',
758 + 'timeout' => $this->_timeout,
759 + 'blocking' => true,
760 + 'compress' => false,
761 + 'decompress' => true,
762 + 'user-agent' => $ha['user-agent']
763 + );
452 764
453 - $buf = explode("\r\n\r\n", $buf, 2);
454 - if(count($buf) != 2) {
455 - throw new DatafeedrHTTPError("Invalid response");
456 - }
457 - if(preg_match('/HTTP.+?(\d\d\d)/', $buf[0], $match)) {
458 - $status = intval($match[1]);
765 + $res = wp_remote_post( $url, $args );
766 +
767 + if ( is_wp_error( $res ) ) {
768 + $code = $res->get_error_code();
769 + $message = $res->get_error_message();
770 +
771 + if ( $code === 'http_request_failed' ) {
772 + throw new DatafeedrConnectionError( $message );
459 773 } else {
460 - throw new DatafeedrHTTPError("Invalid status");
774 + throw new DatafeedrHTTPError( $message );
461 775 }
462 - return array($status, $buf[1]);
463 776 }
777 +
778 + return array( $res['response']['code'], $res['body'] );
464 779 }
465 780 }
466 781
467 -if(!class_exists('DatafeedrSearchRequestBase', false)) {
782 +/**
783 + * Generic Datafeedr API search request.
784 + */
785 +class DatafeedrSearchRequestBase {
786 +
468 787 /**
469 - * Generic Datafeedr API search request.
470 - **/
471 - class DatafeedrSearchRequestBase
472 - {
473 - protected $_api;
474 - protected $_lastResponse;
788 + * The DatafeedrAPI object.
789 + *
790 + * @since 1.0.0
791 + * @var DatafeedrAPI $_api
792 + */
793 + protected $_api;
475 794
476 - /**
477 - * Constructor.
478 - *
479 - * @param object $api DatafeedrApi object.
480 - *
481 - **/
482 - public function __construct($api) {
483 - $this->_api = $api;
484 - }
795 + /**
796 + * An array containing the full response of the last API request.
797 + *
798 + * @since 1.0.0
799 + * @var array $_lastResponse Response array.
800 + */
801 + protected $_lastResponse;
485 802
486 - /**
487 - * Get the number of found products.
488 - *
489 - * @return int
490 - *
491 - **/
492 - public function getFoundCount() {
493 - return $this->_responseItem('found_count', 0);
494 - }
803 + /**
804 + * DatafeedrSearchRequestBase constructor.
805 + *
806 + * @since 1.0.0
807 + *
808 + * @param DatafeedrApi $api
809 + *
810 + */
811 + public function __construct( $api ) {
812 + $this->_api = $api;
813 + }
495 814
496 - /**
497 - * Get the number of products that can be retrieved from the server.
498 - *
499 - * @return int
500 - *
501 - **/
502 - public function getResultCount() {
503 - return $this->_responseItem('result_count', 0);
815 + /**
816 + * Get the number of found products.
817 + *
818 + * @since 1.0.0
819 + *
820 + * @return integer
821 + */
822 + public function getFoundCount() {
823 + return $this->_responseItem( 'found_count', 0 );
824 + }
825 +
826 + /**
827 + * Get the number of products that can be retrieved from the server.
828 + *
829 + * @since 1.0.0
830 + *
831 + * @return integer
832 + */
833 + public function getResultCount() {
834 + return $this->_responseItem( 'result_count', 0 );
835 + }
836 +
837 + /**
838 + * Get the complexity score of the current query.
839 + *
840 + * @since 1.2.12
841 + * @return int
842 + * @throws DatafeedrError
843 + */
844 + public function getQueryScore() {
845 + return abs( (int) $this->_responseItem( 'score', 0 ) );
846 + }
847 +
848 + /**
849 + * Returns the full response from the last search.
850 + *
851 + * Possible items in array include the following:
852 + *
853 + * Array (
854 + * 'found_count' => integer,
855 + * 'length' => integer,
856 + * 'merchants' => array,
857 + * 'networks' => array,
858 + * 'price_groups' => array,
859 + * 'products' => array,
860 + * 'result_count' => integer,
861 + * 'status' => array,
862 + * 'time' => integer,
863 + * 'version' => string,
864 + * )
865 + *
866 + * @since 1.0.0
867 + *
868 + * @return array An array of the full response.
869 + */
870 + public function getResponse() {
871 + return $this->_lastResponse;
872 + }
873 +
874 + /**
875 + * Returns a specific item or property from the response data.
876 + *
877 + * @since 1.0.0
878 + *
879 + * @param mixed $default Return if $prop is not found in the array or object.
880 + *
881 + * @param string $prop The item or property to get from the response array or object.
882 + *
883 + * @return mixed Specific item or property from response data.
884 + * @throws DatafeedrError Throws error if $this->_lastResponse is NULL.
885 + *
886 + */
887 + protected function _responseItem( $prop, $default ) {
888 +
889 + if ( is_null( $this->_lastResponse ) ) {
890 + throw new DatafeedrError( "Reading from an empty request" );
504 891 }
505 892
506 - /**
507 - * Return the response from the last search.
508 - *
509 - * @return array
510 - *
511 - **/
512 - public function getResponse() {
513 - return $this->_lastResponse;
893 + if ( is_object( $this->_lastResponse ) && isset( $this->_lastResponse->$prop ) ) {
894 + return $this->_lastResponse->$prop;
514 895 }
515 896
516 - protected function _responseItem($prop, $default) {
517 - if(is_null($this->_lastResponse)) {
518 - throw new DatafeedrError("Reading from an empty request");
519 - }
520 - if(is_object($this->_lastResponse) && isset($this->_lastResponse->$prop)) {
521 - return $this->_lastResponse->$prop;
522 - }
523 - if(is_array($this->_lastResponse) && isset($this->_lastResponse[$prop])) {
524 - return $this->_lastResponse[$prop];
525 - }
526 - return $default;
897 + if ( is_array( $this->_lastResponse ) && isset( $this->_lastResponse[ $prop ] ) ) {
898 + return $this->_lastResponse[ $prop ];
527 899 }
528 900
529 - function _apiCall($action, $request = NULL) {
530 - $this->_lastResponse = $this->_api->apiCall($action, $request);
531 - }
901 + return $default;
902 + }
532 903
904 + /**
905 + * Sets the $_lastResponse property to the the full response from the last API request.
906 + *
907 + * @since 1.0.0
908 + *
909 + * @param array $request The current API request.
910 + *
911 + * @param string $action The request action (ex. status, search, merchants, networks, etc...)
912 + */
913 + function _apiCall( $action, $request = null ) {
914 + $this->_lastResponse = $this->_api->apiCall( $action, $request );
533 915 }
534 916 }
535 917
536 -if(!class_exists('DatafeedrSearchRequest', false)) {
918 +/**
919 + * Class DatafeedrSearchRequest
920 + *
921 + * Search request for Datafeedr API.
922 + */
923 +class DatafeedrSearchRequest extends DatafeedrSearchRequestBase {
924 +
925 + protected $_query;
926 + protected $_sort;
927 + protected $_fields;
928 + protected $_limit;
929 + protected $_offset;
930 + protected $_priceGroups;
931 + protected $_excludeDuplicates;
932 + protected $_merchantLimit;
933 +
537 934 /**
538 - * Search request for Datafeedr API.
539 - **/
540 - class DatafeedrSearchRequest extends DatafeedrSearchRequestBase
541 - {
542 - /**
543 - * Constructor.
544 - *
545 - * @param object $api DatafeedrApi object.
546 - *
547 - **/
548 - public function __construct($api) {
549 - parent::__construct($api);
935 + * DatafeedrSearchRequest constructor.
936 + *
937 + * @since 1.0.0
938 + *
939 + * @param DatafeedrApi $api
940 + *
941 + */
942 + public function __construct( $api ) {
550 943
551 - $this->_query = array();
552 - $this->_sort = array();
553 - $this->_fields = array();
554 - $this->_limit = 0;
555 - $this->_offset = 0;
556 - $this->_priceGroups = 0;
557 - $this->_excludeDuplicates = "";
944 + parent::__construct( $api );
945 +
946 + $this->_query = array();
947 + $this->_sort = array();
948 + $this->_fields = array();
949 + $this->_limit = 0;
950 + $this->_offset = 0;
951 + $this->_priceGroups = 0;
952 + $this->_excludeDuplicates = '';
953 + $this->_merchantLimit = 0;
954 + }
955 +
956 + /**
957 + * Add a query filter.
958 + *
959 + * @since 1.0.0
960 + *
961 + * @param string $filter Query filter.
962 + *
963 + * @return DatafeedrSearchRequest Returns $this.
964 + */
965 + public function addFilter( $filter ) {
966 + $this->_query[] = $filter;
967 +
968 + return $this;
969 + }
970 +
971 + /**
972 + * Adds a sort field.
973 + *
974 + * @since 1.0.0
975 + *
976 + * @param integer $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
977 + *
978 + * @param string $field Field name.
979 + *
980 + * @return DatafeedrSearchRequest Returns $this.
981 + * @throws DatafeedrError Throws error if sort order is invalid.
982 + *
983 + */
984 + public function addSort( $field, $order = DatafeedrApi::SORT_ASCENDING ) {
985 +
986 + if ( strlen( $field ) && ( $field[0] == '+' || $field[0] == '-' ) ) {
987 + $this->_sort [] = $field;
988 + } else if ( $order == DatafeedrApi::SORT_ASCENDING ) {
989 + $this->_sort [] = '+' . $field;
990 + } else if ( $order == DatafeedrApi::SORT_DESCENDING ) {
991 + $this->_sort [] = '-' . $field;
992 + } else {
993 + throw new DatafeedrError( "Invalid sort order" );
558 994 }
559 995
560 - /**
561 - * Add a query filter.
562 - *
563 - * @param string $filter Query filter.
564 - * @return $this
565 - *
566 - **/
567 - public function addFilter($filter) {
568 - $this->_query []= $filter;
569 - return $this;
996 + return $this;
997 + }
998 +
999 + /**
1000 + * Set which fields to retrieve.
1001 + *
1002 + * @since 1.0.0
1003 + *
1004 + * @param array $fields An array of fields to return for each requested item.
1005 + *
1006 + * Example:
1007 + *
1008 + * Array (
1009 + * 'name',
1010 + * 'price',
1011 + * 'description',
1012 + * 'url',
1013 + * )
1014 + *
1015 + * @return DatafeedrSearchRequest Returns $this.
1016 + */
1017 + public function setFields( $fields ) {
1018 + $this->_fields = $fields;
1019 +
1020 + return $this;
1021 + }
1022 +
1023 + /**
1024 + * Exclude duplicate filter.
1025 + *
1026 + * @since 1.0.0
1027 + *
1028 + * @param string $filter Equality filter in form "field1 field2 | field3".
1029 + *
1030 + * @return DatafeedrSearchRequest Returns $this.
1031 + */
1032 + public function excludeDuplicates( $filter ) {
1033 +
1034 + if ( is_array( $filter ) ) {
1035 + $filter = implode( ' ', $filter );
570 1036 }
571 1037
572 - /**
573 - * Add a sort field.
574 - *
575 - * @param string $field Field name.
576 - * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
577 - * @return $this
578 - *
579 - **/
580 - public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
581 - if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
582 - $this->_sort []= $field;
583 - } else if($order == DatafeedrApi::SORT_ASCENDING) {
584 - $this->_sort []= '+' . $field;
585 - } else if($order == DatafeedrApi::SORT_DESCENDING) {
586 - $this->_sort []= '-' . $field;
587 - } else {
588 - throw new DatafeedrError("Invalid sort order");
589 - }
590 - return $this;
1038 + $this->_excludeDuplicates = $filter;
1039 +
1040 + return $this;
1041 + }
1042 +
1043 + /**
1044 + * Set a limit of number of records to return.
1045 + *
1046 + * @since 1.0.0
1047 + *
1048 + * @param integer $limit The maximum number of records to return.
1049 + *
1050 + * @return DatafeedrSearchRequest Returns $this.
1051 + */
1052 + public function setLimit( $limit ) {
1053 + $this->_limit = $limit;
1054 +
1055 + return $this;
1056 + }
1057 +
1058 + /**
1059 + * Set an offset for the search.
1060 + *
1061 + * @since 1.0.0
1062 + *
1063 + * @param integer $offset The offset.
1064 + *
1065 + * @return DatafeedrSearchRequest Returns $this.
1066 + */
1067 + public function setOffset( $offset ) {
1068 + $this->_offset = $offset;
1069 +
1070 + return $this;
1071 + }
1072 +
1073 + /**
1074 + * Set a limit of results by merchant.
1075 + *
1076 + * @since 2.0.3
1077 + *
1078 + * @param integer $limit The limit.
1079 + *
1080 + * @return DatafeedrSearchRequest Returns $this.
1081 + */
1082 + public function setMerchantLimit( $limit ) {
1083 + $this->_merchantLimit = $limit;
1084 +
1085 + return $this;
1086 + }
1087 +
1088 + /**
1089 + * Set a price group count.
1090 + *
1091 + * This should be used in conjunction with the $this->getPriceGroups() method.
1092 + *
1093 + * Setting $groups to 3 will organize the products into 3 price groups like this:
1094 + *
1095 + * Array (
1096 + * [0] => Array (
1097 + * [product_count] => 321
1098 + * [max] => 9633332
1099 + * [min] => 0
1100 + * )
1101 + * [1] => Array (
1102 + * [product_count] => 116
1103 + * [max] => 19266665
1104 + * [min] => 9633333
1105 + * )
1106 + * [2] => Array (
1107 + * [product_count] => 43
1108 + * [max] => 28900000
1109 + * [min] => 19266666
1110 + * )
1111 + * )
1112 + *
1113 + * @since 1.0.0
1114 + *
1115 + * @param integer $groups Number of price groups to create.
1116 + *
1117 + * @return DatafeedrSearchRequest Returns $this.
1118 + */
1119 + public function setPriceGroups( $groups ) {
1120 + $this->_priceGroups = $groups;
1121 +
1122 + return $this;
1123 + }
1124 +
1125 + /**
1126 + * Get networks found in this request.
1127 + *
1128 + * @since 1.0.0
1129 + *
1130 + * @return array
1131 + */
1132 + public function getNetworks() {
1133 + return $this->_responseItem( 'networks', array() );
1134 + }
1135 +
1136 + /**
1137 + * Get merchants found in this request.
1138 + *
1139 + * @since 1.0.0
1140 + *
1141 + * @return array
1142 + */
1143 + public function getMerchants() {
1144 + return $this->_responseItem( 'merchants', array() );
1145 + }
1146 +
1147 + /**
1148 + * Get price groups found in this request.
1149 + *
1150 + * This must be used in conjunction with $this->setPriceGroups();
1151 + *
1152 + * Returns an array like this:
1153 + *
1154 + * Array (
1155 + * [0] => Array (
1156 + * [product_count] => 321
1157 + * [max] => 9633332
1158 + * [min] => 0
1159 + * )
1160 + * [1] => Array (
1161 + * [product_count] => 116
1162 + * [max] => 19266665
1163 + * [min] => 9633333
1164 + * )
1165 + * [2] => Array (
1166 + * [product_count] => 43
1167 + * [max] => 28900000
1168 + * [min] => 19266666
1169 + * )
1170 + * )
1171 + *
1172 + * @since 1.0.0
1173 + *
1174 + * @return array An array of price groups and the product count, min and max prices in each group.
1175 + */
1176 + public function getPriceGroups() {
1177 + return $this->_responseItem( 'price_groups', array() );
1178 + }
1179 +
1180 + /**
1181 + * Create a request array to use for querying the API.
1182 + *
1183 + * @since 1.0.0
1184 + *
1185 + * @return array The $request array().
1186 + */
1187 + public function getParams() {
1188 +
1189 + $request = array();
1190 +
1191 + if ( $this->_query ) {
1192 + $request['query'] = $this->_query;
591 1193 }
592 1194
593 - /**
594 - * Set which fields to retrieve.
595 - *
596 - * @param array $fields List of field names.
597 - * @return $this
598 - *
599 - **/
600 - public function setFields($fields) {
601 - $this->_fields = $fields;
602 - return $this;
1195 + if ( $this->_sort ) {
1196 + $request['sort'] = $this->_sort;
603 1197 }
604 1198
605 - /**
606 - * Exclude duplicate results.
607 - *
608 - * @param string $filter Equality filter in form "field1 field2 | field3".
609 - * @return $this
610 - *
611 - **/
612 - public function excludeDuplicates($filter) {
613 - if(is_array($filter)) {
614 - $filter = implode(' ', $filter);
615 - }
616 - $this->_excludeDuplicates = $filter;
617 - return $this;
1199 + if ( $this->_fields ) {
1200 + $request['fields'] = $this->_fields;
618 1201 }
619 1202
620 - /**
621 - * Set a limit.
622 - *
623 - * @param int $limit The limit.
624 - * @return $this
625 - *
626 - **/
627 - public function setLimit($limit) {
628 - $this->_limit = $limit;
629 - return $this;
1203 + if ( $this->_limit ) {
1204 + $request['limit'] = $this->_limit;
630 1205 }
631 1206
632 - /**
633 - * Set an offset.
634 - *
635 - * @param int $offset The offset.
636 - * @return $this
637 - *
638 - **/
639 - public function setOffset($offset) {
640 - $this->_offset = $offset;
641 - return $this;
1207 + if ( $this->_offset ) {
1208 + $request['offset'] = $this->_offset;
642 1209 }
643 1210
644 - /**
645 - * Set a price group count.
646 - *
647 - * @param int $groups Group count.
648 - * @return $this
649 - *
650 - **/
651 - public function setPriceGroups($groups) {
652 - $this->_priceGroups = $groups;
653 - return $this;
1211 + if ( $this->_priceGroups ) {
1212 + $request['price_groups'] = $this->_priceGroups;
654 1213 }
655 1214
656 - /**
657 - * Get found networks.
658 - *
659 - * @return array
660 - *
661 - **/
662 - public function getNetworks() {
663 - return $this->_responseItem('networks', array());
1215 + if ( $this->_merchantLimit ) {
1216 + $request['merchant_limit'] = $this->_merchantLimit;
664 1217 }
665 1218
666 - /**
667 - * Get found merchants.
668 - *
669 - * @return array
670 - *
671 - **/
672 - public function getMerchants() {
673 - return $this->_responseItem('merchants', array());
1219 + if ( $this->_excludeDuplicates ) {
1220 + $request['exclude_duplicates'] = $this->_excludeDuplicates;
674 1221 }
675 1222
676 - /**
677 - * Get found price groups.
678 - *
679 - * @return array
680 - *
681 - **/
682 - public function getPriceGroups() {
683 - return $this->_responseItem('price_groups', array());
684 - }
1223 + $request['string_ids'] = 1;
685 1224
686 - /**
687 - * Create a request object to use with the API.
688 - *
689 - * @return array
690 - *
691 - **/
692 - public function getParams() {
693 - $request = array();
694 - if($this->_query) {
695 - $request['query'] = $this->_query;
696 - }
697 - if($this->_sort) {
698 - $request['sort'] = $this->_sort;
699 - }
700 - if($this->_fields) {
701 - $request['fields'] = $this->_fields;
702 - }
703 - if($this->_limit) {
704 - $request['limit'] = $this->_limit;
705 - }
706 - if($this->_offset) {
707 - $request['offset'] = $this->_offset;
708 - }
709 - if($this->_priceGroups) {
710 - $request['price_groups'] = $this->_priceGroups;
711 - }
712 - if($this->_excludeDuplicates) {
713 - $request['exclude_duplicates'] = $this->_excludeDuplicates;
714 - }
715 - $request['string_ids'] = 1;
716 - return $request;
1225 + return $request;
1226 + }
1227 +
1228 + /**
1229 + * Run search and return a list of products.
1230 + *
1231 + * @since 1.0.0
1232 + *
1233 + * @return array An array of products.
1234 + * @throws DatafeedrError Throw error if query is empty.
1235 + *
1236 + */
1237 + public function execute() {
1238 +
1239 + $params = $this->getParams();
1240 +
1241 + if ( ! isset( $params['query'] ) ) {
1242 + throw new DatafeedrError( "Query can't be empty" );
717 1243 }
718 1244
719 - /**
720 - * Run search and return a list of products.
721 - *
722 - * @return array
723 - *
724 - **/
725 - public function execute() {
726 - $params = $this->getParams();
727 - if(!isset($params['query'])) {
728 - throw new DatafeedrError("Query can't be empty");
729 - }
730 - $this->_apiCall('search', $params);
731 - return $this->_responseItem('products', array());
732 - }
1245 + $this->_apiCall( 'search', $params );
733 1246
1247 + return $this->_responseItem( 'products', array() );
734 1248 }
735 1249 }
736 1250
737 -if(!class_exists('DatafeedrMerchantSearchRequest', false)) {
1251 +/**
1252 + * Search request for Datafeedr Merchants.
1253 + */
1254 +class DatafeedrMerchantSearchRequest extends DatafeedrSearchRequestBase {
1255 +
1256 + protected $_query;
1257 + protected $_sort;
1258 + protected $_fields;
1259 + protected $_limit;
1260 + protected $_offset;
1261 +
738 1262 /**
739 - * Search request for Datafeedr Merchants.
740 - **/
741 - class DatafeedrMerchantSearchRequest extends DatafeedrSearchRequestBase
742 - {
743 - /**
744 - * Constructor.
745 - *
746 - * @param object $api DatafeedrApi object.
747 - *
748 - **/
749 - public function __construct($api) {
750 - parent::__construct($api);
1263 + * DatafeedrMerchantSearchRequest constructor.
1264 + *
1265 + * @since 1.0.0
1266 + *
1267 + * @param DatafeedrApi $api
1268 + *
1269 + */
1270 + public function __construct( $api ) {
751 1271
752 - $this->_query = array();
753 - $this->_sort = array();
754 - $this->_fields = array();
755 - $this->_limit = 0;
756 - $this->_offset = 0;
1272 + parent::__construct( $api );
1273 +
1274 + $this->_query = array();
1275 + $this->_sort = array();
1276 + $this->_fields = array();
1277 + $this->_limit = 0;
1278 + $this->_offset = 0;
1279 + }
1280 +
1281 + /**
1282 + * Add a query filter.
1283 + *
1284 + * @since 1.0.0
1285 + *
1286 + * @param string $filter Query filter.
1287 + *
1288 + * @return DatafeedrMerchantSearchRequest Returns $this.
1289 + */
1290 + public function addFilter( $filter ) {
1291 + $this->_query [] = $filter;
1292 +
1293 + return $this;
1294 + }
1295 +
1296 + /**
1297 + * Add a sort field.
1298 + *
1299 + * @since 1.0.0
1300 + *
1301 + * @param integer $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
1302 + *
1303 + * @param string $field Field name.
1304 + *
1305 + * @return DatafeedrMerchantSearchRequest Returns $this.
1306 + * @throws DatafeedrError Throw error if invalid sort order.
1307 + *
1308 + */
1309 + public function addSort( $field, $order = DatafeedrApi::SORT_ASCENDING ) {
1310 +
1311 + if ( strlen( $field ) && ( $field[0] == '+' || $field[0] == '-' ) ) {
1312 + $this->_sort [] = $field;
1313 + } else if ( $order == DatafeedrApi::SORT_ASCENDING ) {
1314 + $this->_sort [] = '+' . $field;
1315 + } else if ( $order == DatafeedrApi::SORT_DESCENDING ) {
1316 + $this->_sort [] = '-' . $field;
1317 + } else {
1318 + throw new DatafeedrError( "Invalid sort order" );
757 1319 }
758 1320
759 - /**
760 - * Add a query filter.
761 - *
762 - * @param string $filter Query filter.
763 - * @return $this
764 - *
765 - **/
766 - public function addFilter($filter) {
767 - $this->_query []= $filter;
768 - return $this;
1321 + return $this;
1322 + }
1323 +
1324 + /**
1325 + * Set which fields to retrieve.
1326 + *
1327 + * @since 1.0.0
1328 + *
1329 + * @param array $fields An array of field names.
1330 + *
1331 + * @return DatafeedrMerchantSearchRequest Returns $this.
1332 + */
1333 + public function setFields( $fields ) {
1334 + $this->_fields = $fields;
1335 +
1336 + return $this;
1337 + }
1338 +
1339 + /**
1340 + * Set a limit.
1341 + *
1342 + * @since 1.0.0
1343 + *
1344 + * @param integer $limit Number of items to return.
1345 + *
1346 + * @return DatafeedrMerchantSearchRequest Returns $this.
1347 + */
1348 + public function setLimit( $limit ) {
1349 + $this->_limit = $limit;
1350 +
1351 + return $this;
1352 + }
1353 +
1354 + /**
1355 + * Set an offset.
1356 + *
1357 + * @since 1.0.0
1358 + *
1359 + * @param integer $offset The offset.
1360 + *
1361 + * @return DatafeedrMerchantSearchRequest Returns $this.
1362 + */
1363 + public function setOffset( $offset ) {
1364 + $this->_offset = $offset;
1365 +
1366 + return $this;
1367 + }
1368 +
1369 + /**
1370 + * Get networks found in this request.
1371 + *
1372 + * @since 1.0.0
1373 + *
1374 + * @return array
1375 + */
1376 + public function getNetworks() {
1377 + return $this->_responseItem( 'networks', array() );
1378 + }
1379 +
1380 + /**
1381 + * Get merchants found in this request.
1382 + *
1383 + * @since 1.0.0
1384 + *
1385 + * @return array
1386 + */
1387 + public function getMerchants() {
1388 + return $this->_responseItem( 'merchants', array() );
1389 + }
1390 +
1391 + /**
1392 + * Run search and return an array of merchants.
1393 + *
1394 + * @since 1.0.0
1395 + *
1396 + * @return array Array of merchants
1397 + * @throws DatafeedrError Throws error if query is empty.
1398 + *
1399 + */
1400 + public function execute() {
1401 +
1402 + $params = $this->getParams();
1403 +
1404 + if ( ! isset( $params['query'] ) ) {
1405 + throw new DatafeedrError( "Query can't be empty" );
769 1406 }
770 1407
771 - /**
772 - * Add a sort field.
773 - *
774 - * @param string $field Field name.
775 - * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
776 - * @throws DatafeedrError
777 - * @return $this
778 - *
779 - **/
780 - public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
781 - if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
782 - $this->_sort []= $field;
783 - } else if($order == DatafeedrApi::SORT_ASCENDING) {
784 - $this->_sort []= '+' . $field;
785 - } else if($order == DatafeedrApi::SORT_DESCENDING) {
786 - $this->_sort []= '-' . $field;
787 - } else {
788 - throw new DatafeedrError("Invalid sort order");
789 - }
790 - return $this;
1408 + $this->_apiCall( 'merchant_search', $params );
1409 +
1410 + return $this->_responseItem( 'merchants', array() );
1411 + }
1412 +
1413 + /**
1414 + * Create a request array to use for querying the API.
1415 + *
1416 + * @since 1.0.0
1417 + *
1418 + * @return array The $request array().
1419 + */
1420 + public function getParams() {
1421 +
1422 + $request = array();
1423 +
1424 + if ( $this->_query ) {
1425 + $request['query'] = $this->_query;
791 1426 }
792 1427
793 - /**
794 - * Set which fields to retrieve.
795 - *
796 - * @param array $fields List of field names.
797 - * @return $this
798 - *
799 - **/
800 - public function setFields($fields) {
801 - $this->_fields = $fields;
802 - return $this;
1428 + if ( $this->_sort ) {
1429 + $request['sort'] = $this->_sort;
803 1430 }
804 1431
805 - /**
806 - * Set a limit.
807 - *
808 - * @param int $limit The limit.
809 - * @return $this
810 - *
811 - **/
812 - public function setLimit($limit) {
813 - $this->_limit = $limit;
814 - return $this;
1432 + if ( $this->_fields ) {
1433 + $request['fields'] = $this->_fields;
815 1434 }
816 1435
817 - /**
818 - * Set an offset.
819 - *
820 - * @param int $offset The offset.
821 - * @return $this
822 - *
823 - **/
824 - public function setOffset($offset) {
825 - $this->_offset = $offset;
826 - return $this;
1436 + if ( $this->_limit ) {
1437 + $request['limit'] = $this->_limit;
827 1438 }
828 1439
829 - /**
830 - * Get found networks.
831 - *
832 - * @return array
833 - *
834 - **/
835 - public function getNetworks() {
836 - return $this->_responseItem('networks', array());
1440 + if ( $this->_offset ) {
1441 + $request['offset'] = $this->_offset;
837 1442 }
838 1443
839 - /**
840 - * Get found merchants.
841 - *
842 - * @return array
843 - *
844 - **/
845 - public function getMerchants() {
846 - return $this->_responseItem('merchants', array());
1444 + return $request;
1445 + }
1446 +}
1447 +
1448 +/**
1449 + * Generic Amazon request.
1450 + */
1451 +class DatafeedrAmazonRequest extends DatafeedrSearchRequestBase {
1452 +
1453 + protected $_found = - 1;
1454 +
1455 + protected $_hosts;
1456 + protected $_params;
1457 + protected $_locale;
1458 + protected $_awsAccessKeyId;
1459 + protected $_awsSecretKey;
1460 + protected $_awsAssociateTag;
1461 +
1462 + const AWS_VERSION = "2011-08-01";
1463 +
1464 + /**
1465 + * DatafeedrAmazonRequest constructor
1466 + *
1467 + * @since 1.0.0
1468 + *
1469 + * @param string $awsAccessKeyId Amazon Access Key.
1470 + * @param string $awsSecretKey Amazon Secret Key.
1471 + * @param string $awsAssociateTag Amazon Associate tag.
1472 + * @param string $locale Optional. Amazon locale (two-letter code).
1473 + *
1474 + * @param DatafeedrApi $api
1475 + *
1476 + * @throws DatafeedrError Throws error if Amazon Locale is invalid.
1477 + */
1478 + public function __construct( $api, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale = 'US' ) {
1479 +
1480 + parent::__construct( $api );
1481 +
1482 + $this->_hosts = array(
1483 + 'AU' => 'webservices.amazon.com.au',
1484 + 'BR' => 'webservices.amazon.com.br',
1485 + 'CA' => 'webservices.amazon.ca',
1486 + 'FR' => 'webservices.amazon.fr',
1487 + 'DE' => 'webservices.amazon.de',
1488 + 'IN' => 'webservices.amazon.in',
1489 + 'IT' => 'webservices.amazon.it',
1490 + 'JP' => 'webservices.amazon.co.jp',
1491 + 'MX' => 'webservices.amazon.com.mx',
1492 + 'NL' => 'webservices.amazon.nl',
1493 + 'SG' => 'webservices.amazon.sg',
1494 + 'SA' => 'webservices.amazon.sa',
1495 + 'ES' => 'webservices.amazon.es',
1496 + 'SE' => 'webservices.amazon.se',
1497 + 'TR' => 'webservices.amazon.com.tr',
1498 + 'AE' => 'webservices.amazon.ae',
1499 + 'UK' => 'webservices.amazon.co.uk',
1500 + 'US' => 'webservices.amazon.com',
1501 + );
1502 +
1503 + $this->_params = array();
1504 + $this->_locale = strtoupper( $locale );
1505 +
1506 + if ( ! isset( $this->_hosts[ $this->_locale ] ) ) {
1507 + throw new DatafeedrError( 'Invalid Amazon locale' );
847 1508 }
848 1509
849 - /**
850 - * Run search and return a list of merchants.
851 - *
852 - * @throws DatafeedrError
853 - * @return array
854 - *
855 - **/
856 - public function execute() {
857 - $params = $this->getParams();
858 - if(!isset($params['query'])) {
859 - throw new DatafeedrError("Query can't be empty");
860 - }
861 - $this->_apiCall('merchant_search', $params);
862 - return $this->_responseItem('merchants', array());
863 - }
1510 + $this->_awsAccessKeyId = $awsAccessKeyId;
1511 + $this->_awsSecretKey = $awsSecretKey;
1512 + $this->_awsAssociateTag = $awsAssociateTag;
1513 + }
864 1514
865 - /**
866 - * Create a request object to use with the API.
867 - *
868 - * @return array
869 - *
870 - **/
871 - public function getParams() {
872 - $request = array();
873 - if($this->_query) {
874 - $request['query'] = $this->_query;
875 - }
876 - if($this->_sort) {
877 - $request['sort'] = $this->_sort;
878 - }
879 - if($this->_fields) {
880 - $request['fields'] = $this->_fields;
881 - }
882 - if($this->_limit) {
883 - $request['limit'] = $this->_limit;
884 - }
885 - if($this->_offset) {
886 - $request['offset'] = $this->_offset;
887 - }
888 - return $request;
889 - }
1515 + /**
1516 + * Returns all parameters.
1517 + *
1518 + * @since 1.0.0
1519 + *
1520 + * @return array
1521 + */
1522 + public function getParams() {
1523 + return $this->_params;
890 1524 }
1525 +
1526 + /**
1527 + * Prepare am API request for Amazon.
1528 + *
1529 + * @since 3.0.0
1530 + *
1531 + * @param array $params
1532 + *
1533 + * @param string $operation
1534 + *
1535 + * @return array
1536 + */
1537 + protected function _amazonRequest( $operation, $params ) {
1538 + return array(
1539 + 'amz_access' => $this->_awsAccessKeyId,
1540 + 'amz_key' => $this->_awsSecretKey,
1541 + 'amz_tag' => $this->_awsAssociateTag,
1542 + 'locale' => $this->_locale,
1543 + 'operation' => $operation,
1544 + 'params' => $params,
1545 + );
1546 + }
891 1547 }
892 1548
893 -if(!class_exists('DatafeedrAmazonRequest', false)) {
1549 +/**
1550 + * Class DatafeedrAmazonSearchRequest
1551 + *
1552 + * Amazon search request class.
1553 + */
1554 +class DatafeedrAmazonSearchRequest extends DatafeedrAmazonRequest {
1555 +
894 1556 /**
895 - * Generic Amazon request.
896 - **/
897 - class DatafeedrAmazonRequest extends DatafeedrSearchRequestBase
898 - {
899 - protected $_found = -1;
1557 + * Add a parameter.
1558 + *
1559 + * @since 1.0.0
1560 + *
1561 + * @param string $value Parameter value.
1562 + *
1563 + * @param string $name Parameter name.
1564 + *
1565 + * @return DatafeedrAmazonSearchRequest Returns $this.
1566 + *
1567 + * @see https://webservices.amazon.com/paapi5/documentation/search-items.html#ItemLookup-rp
1568 + */
1569 + public function addParam( $name, $value ) {
1570 + $this->_params[ $name ] = $value;
900 1571
901 - const AWS_VERSION = "2011-08-01";
1572 + return $this;
1573 + }
902 1574
903 - /**
904 - * Constructor
905 - *
906 - * @param object $api DatafeedrApi object.
907 - * @param string $awsAccessKeyId Amazon access key.
908 - * @param string $awsSecretKey Amazon secret key.
909 - * @param string $awsAssociateTag Amazon associate tag.
910 - * @param string $locale Amazon locale (two-letter code).
911 - */
912 - public function __construct($api, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
913 - parent::__construct($api);
914 - $this->_hosts = array(
915 - "CA" => "webservices.amazon.ca",
916 - "CN" => "webservices.amazon.cn",
917 - "DE" => "webservices.amazon.de",
918 - "ES" => "webservices.amazon.es",
919 - "FR" => "webservices.amazon.fr",
920 - "IT" => "webservices.amazon.it",
921 - "JP" => "webservices.amazon.co.jp",
922 - "UK" => "webservices.amazon.co.uk",
923 - "US" => "webservices.amazon.com",
924 - );
1575 + /**
1576 + * Run search and return an array of products.
1577 + *
1578 + * IMPORTANT - The Amazon API returns a MAXIMUM of 10 products per API request and a maximum of
1579 + * 50 products per search query.
1580 + *
1581 + * @since 1.0.0
1582 + *
1583 + * @return array An array of products.
1584 + * @throws DatafeedrError
1585 + */
1586 + public function execute() {
925 1587
926 - $this->_params = array();
927 - $this->_locale = strtoupper($locale);
1588 + $params = array_filter( $this->_params );
1589 + $req = $this->_amazonRequest( 'SearchItems', $params );
1590 + $this->_apiCall( 'amazon_find', $req );
928 1591
929 - if(!isset($this->_hosts[$this->_locale])) {
930 - throw new DatafeedrError("Invalid Amazon locale");
931 - }
1592 + return $this->_responseItem( 'products', array() );
1593 + }
1594 +}
932 1595
933 - $this->_awsAccessKeyId = $awsAccessKeyId;
934 - $this->_awsSecretKey = $awsSecretKey;
935 - $this->_awsAssociateTag = $awsAssociateTag;
936 - }
1596 +/**
1597 + * Class DatafeedrAmazonLookupRequest
1598 + *
1599 + * Amazon lookup request.
1600 + */
1601 +class DatafeedrAmazonLookupRequest extends DatafeedrAmazonRequest {
937 1602
938 - /**
939 - * Returns all parameters.
940 - *
941 - * @return array
942 - *
943 - **/
944 - public function getParams() {
945 - return $this->_params;
946 - }
1603 + /**
1604 + * Add a parameter.
1605 + *
1606 + * @since 1.0.0
1607 + *
1608 + * @param string|array $value Parameter value or an array of values (up to 10).
1609 + *
1610 + * @param string $name Parameter name - one of 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN'
1611 + *
1612 + * @return DatafeedrAmazonLookupRequest Returns $this.
1613 + *
1614 + * @see https://webservices.amazon.com/paapi5/documentation/get-items.html#ItemLookup-rp
1615 + */
1616 + public function addParam( $name, $value ) {
1617 + $this->_params[ $name ] = $value;
947 1618
948 - protected function _amazonUrl($operation, $params, $defaults=NULL) {
949 - $params = array_filter($params);
1619 + return $this;
1620 + }
950 1621
951 - if(!is_null($defaults)) {
952 - foreach($defaults as $k => $v) {
953 - if(!isset($params[$k])) {
954 - $params[$k] = $v;
955 - }
956 - }
957 - }
1622 + /**
1623 + * Run search and return an array of products.
1624 + *
1625 + * @since 1.0.0
1626 + *
1627 + * @return array An array of products.
1628 + */
1629 + public function execute() {
958 1630
959 - $params["Operation"] = $operation;
960 - $params["Service"] = "AWSECommerceService";
961 - $params["AWSAccessKeyId"] = $this->_awsAccessKeyId;
962 - $params["AssociateTag"] = $this->_awsAssociateTag;
963 - $params["Version"] = self::AWS_VERSION;
964 - $params["Timestamp"] = gmdate("Y-m-d\\TH:i:s\\Z");
1631 + $params = array_filter( $this->_params );
1632 + $types = array( 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN', 'asin', 'sku', 'upc', 'ean', 'isbn' );
965 1633
966 - ksort($params);
967 - $query = array();
968 - foreach($params as $k => $v) {
969 - if(is_array($v)) {
970 - $v = implode(',', $v);
1634 + foreach ( $types as $type ) {
1635 + if ( isset( $params[ $type ] ) ) {
1636 + $params['ItemIdType'] = strtoupper( $type );
1637 + $params['ItemIds'] = $params[ $type ];
1638 + if ( is_string( $params['ItemIds'] ) ) {
1639 + $params['ItemIds'] = explode( ',', $params['ItemIds'] );
971 1640 }
972 - $query []= $k . '=' . rawurlencode($v);
1641 + unset( $params[ $type ] );
973 1642 }
974 - $query = implode('&', $query);
975 - $host = $this->_hosts[$this->_locale];
976 - $path = "/onca/xml";
977 - $subj = sprintf("GET\n%s\n%s\n%s", $host, $path, $query);
978 - $sign = rawurlencode(base64_encode(hash_hmac("sha256", $subj, $this->_awsSecretKey, TRUE)));
979 - return "http://{$host}{$path}?{$query}&Signature={$sign}";
980 1643 }
1644 +
1645 + $req = $this->_amazonRequest( 'GetItems', $params );
1646 + $this->_apiCall( 'amazon_find', $req );
1647 +
1648 + return $this->_responseItem( 'products', array() );
981 1649 }
982 1650 }
983 1651
984 -if(!class_exists('DatafeedrAmazonSearchRequest', false)) {
985 - /**
986 - * Amazon search request.
987 - **/
988 - class DatafeedrAmazonSearchRequest extends DatafeedrAmazonRequest
989 - {
990 - /**
991 - * Add a parameter.
992 - *
993 - * @param string $name Parameter name.
994 - * @param string $value Parameter value.
995 - * @return $this
996 - *
997 - * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemSearch.html
998 - *
999 - **/
1000 - public function addParam($name, $value) {
1001 - $this->_params[$name] = $value;
1002 - return $this;
1652 +/** CreatorAPI */
1653 +class DatafeedrAmazonCreatorApiRequest extends DatafeedrSearchRequestBase {
1654 +
1655 + protected $_found = - 1;
1656 +
1657 + protected $_hosts;
1658 + protected $_params;
1659 +// protected $_capiCredentialId;
1660 +// protected $_capiCredentialSecret;
1661 +// protected $_capiVersion;
1662 + protected $_capiPartnerTag;
1663 + protected $_capiMarketplace;
1664 +
1665 + public const AWS_VERSION = "2026-01-05";
1666 +
1667 + public function __construct( $api, $capiMarketplace = 'US' ) {
1668 +
1669 + parent::__construct( $api );
1670 +
1671 + $capiMarketplace = strtoupper( trim( $capiMarketplace ) );
1672 +
1673 + foreach ( dfrapi_get_capi_marketplaces() as $code => $marketplace ) {
1674 + $this->_hosts[ $code ] = $marketplace['domain'];
1003 1675 }
1004 1676
1005 - /**
1006 - * Run search and return a list of products.
1007 - *
1008 - * @return array
1009 - *
1010 - **/
1011 - public function execute() {
1012 - $defaults = array(
1013 - 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1014 - 'SearchIndex' => 'All',
1015 - );
1016 - $url = $this->_amazonUrl('ItemSearch', $this->_params, $defaults);
1017 - $this->_apiCall('amazon_search', array('url' => $url));
1018 - return $this->_responseItem('products', array());
1677 + if ( ! isset( $this->_hosts[ $capiMarketplace ] ) ) {
1678 + throw new DatafeedrError( 'Invalid Amazon CAPI locale' );
1019 1679 }
1680 +
1681 + $this->_params = array();
1682 +
1683 +// $capiVersion = dfrapi_get_capi_marketplace( $capiMarketplace )['region']['version'];
1684 +
1685 +// $this->_capiCredentialId = $capiCredentialId;
1686 +// $this->_capiCredentialSecret = $capiCredentialSecret;
1687 +// $this->_capiVersion = $capiVersion;
1688 +// $this->_capiPartnerTag = $capiPartnerTag;
1689 + $this->_capiMarketplace = $capiMarketplace;
1020 1690 }
1691 +
1692 + /**
1693 + * Returns all parameters.
1694 + *
1695 + * @since 1.0.0
1696 + *
1697 + * @return array
1698 + */
1699 + public function getParams() {
1700 + return $this->_params;
1701 + }
1702 +
1703 + /**
1704 + * Prepare am API request for Amazon.
1705 + *
1706 + * @since 3.0.0
1707 + *
1708 + * @param array $params
1709 + *
1710 + * @param string $operation
1711 + *
1712 + * @return array
1713 + */
1714 +// protected function _amazonRequest( $operation, $params ) {
1715 +// return array(
1716 +// 'capi_credential_id' => $this->_capiCredentialId,
1717 +// 'capi_credential_secret' => $this->_capiCredentialSecret,
1718 +// 'capi_version' => $this->_capiVersion,
1719 +// 'capi_partner_tag' => $this->_capiPartnerTag,
1720 +// 'capi_marketplace' => $this->_capiMarketplace,
1721 +// 'operation' => $operation,
1722 +// 'params' => $params,
1723 +// );
1724 +// }
1021 1725 }
1022 1726
1023 -if(!class_exists('DatafeedrAmazonLookupRequest', false)) {
1727 +/** CreatorAPI */
1728 +class DatafeedrAmazonCreatorApiSearchRequest extends DatafeedrAmazonCreatorApiRequest {
1729 +
1024 1730 /**
1025 - * Amazon lookup request.
1026 - **/
1027 - class DatafeedrAmazonLookupRequest extends DatafeedrAmazonRequest
1028 - {
1029 - /**
1030 - * Add a parameter.
1031 - *
1032 - * @param string $name Parameter name - one of 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN'
1033 - * @param string|array $value Parameter value or an array of values (up to 10).
1034 - * @return $this
1035 - *
1036 - * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemLookup.html
1037 - *
1038 - **/
1039 - public function addParam($name, $value) {
1040 - $this->_params[$name] = $value;
1041 - return $this;
1731 + * Add a parameter.
1732 + *
1733 + * @since 1.0.0
1734 + *
1735 + * @param string $value Parameter value.
1736 + *
1737 + * @param string $name Parameter name.
1738 + *
1739 + * @return DatafeedrAmazonCreatorApiSearchRequest Returns $this.
1740 + *
1741 + * @see https://webservices.amazon.com/paapi5/documentation/search-items.html#ItemLookup-rp
1742 + */
1743 + public function addParam( $name, $value ) {
1744 + $this->_params[ $name ] = $value;
1745 +
1746 + return $this;
1747 + }
1748 +
1749 + /**
1750 + * Run search and return an array of products.
1751 + *
1752 + * IMPORTANT - The Amazon API returns a MAXIMUM of 10 products per API request and a maximum of
1753 + * 50 products per search query.
1754 + *
1755 + * @since 1.0.0
1756 + *
1757 + * @return array An array of products.
1758 + * @throws DatafeedrError
1759 + */
1760 + public function execute() {
1761 +
1762 + $access_token = dfrapi_get_capi_access_token();
1763 +
1764 + if ( is_wp_error( $access_token ) ) {
1765 + throw new DatafeedrError( $access_token->get_error_message() );
1042 1766 }
1043 1767
1044 - /**
1045 - * Run search and return a list of products.
1046 - *
1047 - * @return array
1048 - *
1049 - **/
1050 - public function execute() {
1051 - $params = array_filter($this->_params);
1052 - $types = array('ASIN', 'SKU', 'UPC', 'EAN', 'ISBN', 'asin', 'sku', 'upc', 'ean', 'isbn');
1053 - foreach($types as $type) {
1054 - if(isset($params[$type])) {
1055 - $params['IdType'] = strtoupper($type);
1056 - $params['ItemId'] = $params[$type];
1057 - unset($params[$type]);
1058 - }
1768 + $body = array_merge( array_filter( $this->_params ), [] );
1769 +
1770 + $credentials = dfrapi_get_capi_credentials();
1771 + $marketplace = dfrapi_get_capi_marketplace( $this->_capiMarketplace );
1772 +
1773 + $domain = $marketplace['domain'];
1774 + $credential_version = $marketplace['region']['version'];
1775 + $body['partnerTag'] = $credentials['partner_tag'];
1776 +
1777 + // https://affiliate-program.amazon.com/creatorsapi/docs/en-us/api-reference/operations/search-items
1778 + $resources = [
1779 +// 'browseNodeInfo.browseNodes',
1780 +// 'browseNodeInfo.browseNodes.ancestor',
1781 +// 'browseNodeInfo.browseNodes.salesRank',
1782 +// 'browseNodeInfo.websiteSalesRank',
1783 + 'customerReviews.count',
1784 + 'customerReviews.starRating',
1785 + 'images.primary.highRes',
1786 + 'images.primary.large',
1787 + 'images.primary.medium',
1788 + 'images.primary.small',
1789 +// 'images.variants.highRes',
1790 +// 'images.variants.large',
1791 +// 'images.variants.medium',
1792 +// 'images.variants.small',
1793 + 'itemInfo.byLineInfo',
1794 +// 'itemInfo.classifications',
1795 +// 'itemInfo.contentInfo',
1796 +// 'itemInfo.contentRating',
1797 + 'itemInfo.externalIds',
1798 +// 'itemInfo.features',
1799 +// 'itemInfo.manufactureInfo',
1800 + 'itemInfo.productInfo',
1801 +// 'itemInfo.technicalInfo',
1802 + 'itemInfo.title',
1803 + 'itemInfo.tradeInInfo',
1804 + 'offersV2.listings.availability',
1805 + 'offersV2.listings.condition',
1806 +// 'offersV2.listings.dealDetails',
1807 +// 'offersV2.listings.isBuyBoxWinner',
1808 +// 'offersV2.listings.loyaltyPoints',
1809 +// 'offersV2.listings.merchantInfo',
1810 + 'offersV2.listings.price',
1811 + 'offersV2.listings.type',
1812 + 'parentASIN',
1813 +// 'searchRefinements',
1814 + ];
1815 +
1816 + $body['resources'] = $resources;
1817 +
1818 + $response = wp_remote_post(
1819 + 'https://creatorsapi.amazon/catalog/v1/searchItems',
1820 + [
1821 + 'headers' => [
1822 + 'Authorization' => sprintf(
1823 + 'Bearer %s, Version %s',
1824 + $access_token,
1825 + $credential_version
1826 + ),
1827 + 'Content-Type' => 'application/json',
1828 + 'x-marketplace' => $domain,
1829 + ],
1830 + 'body' => wp_json_encode( $body ),
1831 + 'timeout' => 20,
1832 + 'httpversion' => '1.1', // important for Amazon APIs
1833 + ]
1834 + );
1835 +
1836 + if ( is_wp_error( $response ) ) {
1837 + error_log( $response->get_error_message() );
1838 +
1839 + throw new DatafeedrConnectionError( $response->get_error_message() );
1840 + }
1841 +
1842 + $status = wp_remote_retrieve_response_code( $response );
1843 +
1844 + if ( 404 === $status ) {
1845 + $body = wp_remote_retrieve_body( $response );
1846 + $data = json_decode( $body, true );
1847 + if ( isset( $data['type'] ) && 'ResourceNotFoundException' === $data['type'] ) {
1848 + return [];
1059 1849 }
1850 + }
1060 1851
1061 - $defaults = array(
1062 - 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1063 - );
1064 - if(isset($params['IdType']) && $params['IdType'] != 'ASIN') {
1065 - $defaults['SearchIndex'] = 'All';
1852 + if ( 200 !== $status ) {
1853 + $error_body = wp_remote_retrieve_body( $response );
1854 + $error_data = json_decode( $error_body, true );
1855 + $status_message = wp_remote_retrieve_response_message( $response );
1856 +
1857 + if ( ! empty( $error_data['message'] ) ) {
1858 + $message = $error_data['message'];
1859 + } elseif ( ! empty( $error_data['reason'] ) ) {
1860 + $message = $error_data['reason'];
1861 + } else {
1862 + $message = $status_message;
1066 1863 }
1067 - $url = $this->_amazonUrl('ItemLookup', $params, $defaults);
1068 - $this->_apiCall('amazon_search', array('url' => $url));
1069 - return $this->_responseItem('products', array());
1864 +
1865 + error_log( sprintf( '[Datafeedr CAPI] SearchItems error (%d): %s | Response: %s', $status, $message, $error_body ) );
1866 +
1867 + throw new DatafeedrHTTPError( $message, $status );
1070 1868 }
1869 +
1870 + $body = wp_remote_retrieve_body( $response );
1871 +
1872 +
1873 + /*
1874 +
1875 + [
1876 + "errors" => null,
1877 + "searchResult" => [
1878 + "items" => [
1879 + [
1880 + "asin" => "0545162076",
1881 + "browseNodeInfo" => null,
1882 + "customerReviews" => null,
1883 + "detailPageURL" => "https://www.amazon.com/dp/0545162076?tag=xyz-20&linkCode=osi&th=1&psc=1",
1884 + "images" => null,
1885 + "itemInfo" => [
1886 + "byLineInfo" => null,
1887 + "classifications" => null,
1888 + "contentInfo" => null,
1889 + "contentRating" => null,
1890 + "externalIds" => null,
1891 + "features" => null,
1892 + "manufactureInfo" => null,
1893 + "productInfo" => null,
1894 + "technicalInfo" => null,
1895 + "title" => [
1896 + "displayValue" => "Harry Potter Paperback Box Set (Books 1-7)",
1897 + "label" => "Title",
1898 + "locale" => "en_US",
1899 + ],
1900 + "tradeInInfo" => null,
1901 + ],
1902 + "offersV2" => null,
1903 + "parentASIN" => null,
1904 + "score" => null,
1905 + "variationAttributes" => null,
1906 + ],
1907 + [ ... ],
1908 + [ ... ],
1909 + [ ... ],
1910 + ],
1911 + "searchRefinements" => null,
1912 + "searchURL" => "https://www.amazon.com/s?k=Harry+Potter&rh=p_n_availability%3A2661600011&tag=xyz-20&linkCode=osi",
1913 + "totalResultCount" => 306,
1914 + ],
1915 + ]
1916 +
1917 +
1918 + */
1919 + /**
1920 + * [
1921 + * "errors" => null,
1922 + * "searchResult" => [
1923 + * "items" => [
1924 + * [
1925 + * "asin" => "0545162076",
1926 + * "browseNodeInfo" => null,
1927 + * "customerReviews" => null,
1928 + * "detailPageURL" => "https://www.amazon.com/dp/0545162076?tag=xyz-20&linkCode=osi&th=1&psc=1",
1929 + * "images" => null,
1930 + * "itemInfo" => [
1931 + * "byLineInfo" => null,
1932 + * "classifications" => null,
1933 + * "contentInfo" => null,
1934 + * "contentRating" => null,
1935 + * "externalIds" => null,
1936 + * "features" => null,
1937 + * "manufactureInfo" => null,
1938 + * "productInfo" => null,
1939 + * "technicalInfo" => null,
1940 + * "title" => [
1941 + * "displayValue" => "Harry Potter Paperback Box Set (Books 1-7)",
1942 + * "label" => "Title",
1943 + * "locale" => "en_US",
1944 + * ],
1945 + * "tradeInInfo" => null,
1946 + * ],
1947 + * "offersV2" => null,
1948 + * "parentASIN" => null,
1949 + * "score" => null,
1950 + * "variationAttributes" => null,
1951 + * ],
1952 + * [ ... ],
1953 + * [ ... ],
1954 + * [ ... ],
1955 + * ],
1956 + * "searchRefinements" => null,
1957 + * "searchURL" => "https://www.amazon.com/s?k=Harry+Potter&rh=p_n_availability%3A2661600011&tag=xyz-20&linkCode=osi",
1958 + * "totalResultCount" => 306,
1959 + * ],
1960 + * ]
1961 + */
1962 + $data = json_decode( $body, true );
1963 +
1964 + if ( ! empty( $data['errors'] ) ) {
1965 + $error = $data['errors'][0];
1966 + error_log( $error['message'] );
1967 +
1968 + throw new DatafeedrExternalError( $error['message'] );
1969 + }
1970 +
1971 + $items = $data['searchResult']['items'] ?? [];
1972 + $products = [];
1973 +
1974 + foreach ( $items as $item ) {
1975 + $products[] = dfrapi_transform_capi_item_into_datafeedr_product_array( $item );
1976 + }
1977 +
1978 + return $products;
1979 +
1980 +// $data now contains the API response
1981 +
1982 +
1071 1983 }
1072 1984 }
1073 1985
1074 -if(!class_exists('DatafeedrError', false)) {
1075 - /**
1076 - * Generic Api error.
1077 - **/
1078 - class DatafeedrError extends Exception
1079 - {
1080 - }
1986 +/** CreatorAPI */
1987 +//class DatafeedrAmazonCreatorApiLookupRequest extends DatafeedrAmazonCreatorApiRequest {
1988 +//
1989 +// /**
1990 +// * Add a parameter.
1991 +// *
1992 +// * @since 1.0.0
1993 +// *
1994 +// * @param string|array $value Parameter value or an array of values (up to 10).
1995 +// *
1996 +// * @param string $name Parameter name - one of 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN'
1997 +// *
1998 +// * @return DatafeedrAmazonCreatorApiLookupRequest Returns $this.
1999 +// *
2000 +// * @see https://webservices.amazon.com/paapi5/documentation/get-items.html#ItemLookup-rp
2001 +// */
2002 +// public function addParam( $name, $value ) {
2003 +// $this->_params[ $name ] = $value;
2004 +//
2005 +// return $this;
2006 +// }
2007 +//
2008 +// /**
2009 +// * Run search and return an array of products.
2010 +// *
2011 +// * @since 1.0.0
2012 +// *
2013 +// * @return array An array of products.
2014 +// */
2015 +// public function execute() {
2016 +//
2017 +// $params = array_filter( $this->_params );
2018 +// $types = array( 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN', 'asin', 'sku', 'upc', 'ean', 'isbn' );
2019 +//
2020 +// foreach ( $types as $type ) {
2021 +// if ( isset( $params[ $type ] ) ) {
2022 +// $params['itemIdType'] = strtoupper( $type );
2023 +// $params['itemIds'] = $params[ $type ];
2024 +// if ( is_string( $params['itemIds'] ) ) {
2025 +// $params['itemIds'] = explode( ',', $params['itemIds'] );
2026 +// }
2027 +// unset( $params[ $type ] );
2028 +// }
2029 +// }
2030 +//
2031 +// $req = $this->_amazonRequest( 'GetItems', $params );
2032 +// $this->_apiCall( 'amazon_find', $req );
2033 +//
2034 +// return $this->_responseItem( 'products', array() );
2035 +// }
2036 +//}
2037 +
2038 +/**
2039 + * Class DatafeedrError.
2040 + *
2041 + * Generic Api error.
2042 + */
2043 +class DatafeedrError extends Exception {
1081 2044 }
1082 2045
1083 -if(!class_exists('DatafeedrBadRequestError', false)) {
1084 - /**
1085 - * API error: Invalid Request.
1086 - **/
1087 - class DatafeedrBadRequestError extends DatafeedrError
1088 - {
1089 - }
2046 +/**
2047 + * Class DatafeedrBadRequestError.
2048 + *
2049 + * API error: Invalid Request.
2050 + */
2051 +class DatafeedrBadRequestError extends DatafeedrError {
1090 2052 }
1091 2053
1092 -if(!class_exists('DatafeedrAuthenticationError', false)) {
1093 - /**
1094 - * API error: Authentication failed.
1095 - **/
1096 - class DatafeedrAuthenticationError extends DatafeedrError
1097 - {
1098 - }
2054 +/**
2055 + * Class DatafeedrAuthenticationError.
2056 + *
2057 + * API error: Authentication failed.
2058 + */
2059 +class DatafeedrAuthenticationError extends DatafeedrError {
1099 2060 }
1100 2061
1101 -if(!class_exists('DatafeedrLimitExceededError', false)) {
1102 - /**
1103 - * API error: Query limit exceeded.
1104 - **/
1105 - class DatafeedrLimitExceededError extends DatafeedrError
1106 - {
1107 - }
2062 +/**
2063 + * Class DatafeedrLimitExceededError.
2064 + *
2065 + * API error: Query limit exceeded.
2066 + */
2067 +class DatafeedrLimitExceededError extends DatafeedrError {
1108 2068 }
1109 2069
1110 -if(!class_exists('DatafeedrHTTPError', false)) {
1111 - /**
1112 - * API error: Unspecified HTTP error.
1113 - **/
1114 - class DatafeedrHTTPError extends DatafeedrError
1115 - {
1116 - }
2070 +/**
2071 + * Class DatafeedrHTTPError.
2072 + *
2073 + * API error: Unspecified HTTP error.
2074 + */
2075 +class DatafeedrHTTPError extends DatafeedrError {
1117 2076 }
1118 2077
1119 -if(!class_exists('DatafeedrQueryError', false)) {
1120 - /**
1121 - * API error: Error in the search query.
1122 - **/
1123 - class DatafeedrQueryError extends DatafeedrError
1124 - {
1125 - }
2078 +/**
2079 + * Class DatafeedrConnectionError.
2080 + *
2081 + * API error: Connection error.
2082 + */
2083 +class DatafeedrConnectionError extends DatafeedrError {
1126 2084 }
1127 2085
1128 -if(!class_exists('DatafeedrExternalError', false)) {
1129 - /**
1130 - * API error: External service error.
1131 - **/
1132 - class DatafeedrExternalError extends DatafeedrError
1133 - {
1134 - }
2086 +/**
2087 + * Class DatafeedrQueryError.
2088 + *
2089 + * API error: Error in the search query.
2090 + */
2091 +class DatafeedrQueryError extends DatafeedrError {
1135 2092 }
1136 2093
1137 -if(!class_exists('DatafeedrServerError', false)) {
1138 - /**
1139 - * API error: Internal server error.
1140 - **/
1141 - class DatafeedrServerError extends DatafeedrError
1142 - {
1143 - }
2094 +/**
2095 + * Class DatafeedrExternalError.
2096 + *
2097 + * API error: External service error.
2098 + */
2099 +class DatafeedrExternalError extends DatafeedrError {
1144 2100 }
1145 2101
1146 -?>
2102 +/**
2103 + * Class DatafeedrServerError.
2104 + *
2105 + * API error: Internal server error.
2106 + */
2107 +class DatafeedrServerError extends DatafeedrError {
2108 +}