MWSClient   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 268
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 6
dl 0
loc 268
rs 9.76
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 4
A setMarketPlaces() 0 5 2
A getCurrentMarketPlaces() 0 4 1
A getTimeStamp() 0 4 1
A getAccessKeyId() 0 4 1
A setAccessKeyId() 0 6 1
A getSellerId() 0 4 1
A setSellerId() 0 6 1
A getMWSAuthToken() 0 4 1
A getSignatureMethod() 0 4 1
A getSignatureVersion() 0 4 1
A getDomain() 0 11 2
A getCountry() 0 4 1
A setCountry() 0 10 2
A getMarketPlaceIds() 0 4 1
A post() 0 33 4
A getDefaultQueryParams() 0 19 1
A getMarketPlaceParams() 0 16 3
A generateRequestUri() 0 4 1
A getQueryStringForSignature() 0 10 1
A generateSignature() 0 13 1
A getQuery() 0 7 1
1
<?php
2
3
namespace Looxis\LaravelAmazonMWS;
4
5
use GuzzleHttp\Client;
6
use Illuminate\Support\Arr;
7
use Looxis\LaravelAmazonMWS\Exceptions\CountryIsMissingException;
8
use Looxis\LaravelAmazonMWS\Exceptions\CountryNotAvailableException;
9
10
class MWSClient
11
{
12
    const SIGNATURE_METHOD = 'HmacSHA256';
13
    const SIGNATURE_VERSION = '2';
14
    const DATE_FORMAT = "Y-m-d\TH:i:s.\\0\\0\\0\\Z";
15
    const APPLICATION_NAME = 'Looxis/MwsClient';
16
    const APPLICATION_VERSION = '0.0.1';
17
18
    protected $accessKeyId;
19
    protected $secretKey;
20
    protected $sellerId;
21
    protected $client;
22
    protected $marketPlaces;
23
    protected $mwsAuthToken;
24
25
    protected $marketplaceIds = [
26
        'A2Q3Y263D00KWC' => 'mws.amazonservices.com',
27
        'A2EUQ1WTGCTBG2' => 'mws.amazonservices.ca',
28
        'A1AM78C64UM0Y8' => 'mws.amazonservices.com.mx',
29
        'ATVPDKIKX0DER' => 'mws.amazonservices.com',
30
        'A2VIGQ35RCS4UG' => 'mws.amazonservices.ae',
31
        'A1PA6795UKMFR9' => 'mws-eu.amazonservices.com',
32
        'ARBP9OOSHTCHU' => 'mws-eu.amazonservices.com',
33
        'A1RKKUPIHCS9HS' => 'mws-eu.amazonservices.com',
34
        'A13V1IB3VIYZZH' => 'mws-eu.amazonservices.com',
35
        'A1F83G8C2ARO7P' => 'mws-eu.amazonservices.com',
36
        'A21TJRUUN4KGV' => 'mws.amazonservices.in',
37
        'APJ6JRA9NG5V4' => 'mws-eu.amazonservices.com',
38
        'A17E79C6D8DWNP' => 'mws-eu.amazonservices.com',
39
        'A33AVAJ2PDY3EV' => 'mws-eu.amazonservices.com',
40
        'A19VAU5U5O7RUS' => 'mws-fe.amazonservices.com',
41
        'A39IBJ37TRP1C6' => 'mws.amazonservices.com.au',
42
        'A1VC38T7YXB528' => 'mws.amazonservices.jp',
43
        'A1805IZSGTT6HS' => 'mws-eu.amazonservices.com',
44
        'A1C3SOZRARQ6R3' => 'mws-eu.amazonservices.com',
45
        'A2NODRKZP88ZB9' => 'mws-eu.amazonservices.com',
46
    ];
47
48
    protected $countries = [
49
        'BR' => 'A2Q3Y263D00KWC',
50
        'CA' => 'A2EUQ1WTGCTBG2',
51
        'MX' => 'A1AM78C64UM0Y8',
52
        'US' => 'ATVPDKIKX0DER',
53
        'AE' => 'A2VIGQ35RCS4UG',
54
        'DE' => 'A1PA6795UKMFR9',
55
        'EG' => 'ARBP9OOSHTCHU',
56
        'ES' => 'A1RKKUPIHCS9HS',
57
        'FR' => 'A13V1IB3VIYZZH',
58
        'GB' => 'A1F83G8C2ARO7P',
59
        'IN' => 'A21TJRUUN4KGV',
60
        'IT' => 'APJ6JRA9NG5V4',
61
        'SA' => 'A17E79C6D8DWNP',
62
        'TR' => 'A33AVAJ2PDY3EV',
63
        'SG' => 'A19VAU5U5O7RUS',
64
        'AU' => 'A39IBJ37TRP1C6',
65
        'JP' => 'A1VC38T7YXB528',
66
        'NL' => 'A1805IZSGTT6HS',
67
        'PL' => 'A1C3SOZRARQ6R3',
68
        'SE' => 'A2NODRKZP88ZB9',
69
    ];
70
71
    public function __construct(Client $client = null)
72
    {
73
        $this->accessKeyId = config('amazon-mws.access_key_id');
74
        $this->secretKey = config('amazon-mws.secret_key');
75
        $this->sellerId = config('amazon-mws.seller_id');
76
        $this->mwsAuthToken = config('amazon-mws.mws_auth_token') ?: null;
77
        $this->marketPlaces = explode(',', config('amazon-mws.default_market_place') ?: 'DE');
78
        $this->client = $client ?: new Client(['timeout'  => 60]);
79
    }
80
81
    public function setMarketPlaces($countryCodes)
82
    {
83
        $countryCodes = is_array($countryCodes) ? $countryCodes : func_get_args();
84
        $this->marketPlaces = $countryCodes;
85
    }
86
87
    public function getCurrentMarketPlaces()
88
    {
89
        return $this->marketPlaces;
90
    }
91
92
    public function getTimeStamp()
93
    {
94
        return gmdate(self::DATE_FORMAT, time());
95
    }
96
97
    public function getAccessKeyId()
98
    {
99
        return $this->accessKeyId;
100
    }
101
102
    public function setAccessKeyId($key)
103
    {
104
        $this->accessKeyId = $key;
105
106
        return $this;
107
    }
108
109
    public function getSellerId()
110
    {
111
        return $this->sellerId;
112
    }
113
114
    public function setSellerId($id)
115
    {
116
        $this->sellerId = $id;
117
118
        return $this;
119
    }
120
121
    public function getMWSAuthToken()
122
    {
123
        return $this->mwsAuthToken;
124
    }
125
126
    public function getSignatureMethod()
127
    {
128
        return self::SIGNATURE_METHOD;
129
    }
130
131
    public function getSignatureVersion()
132
    {
133
        return self::SIGNATURE_VERSION;
134
    }
135
136
    public function getDomain()
137
    {
138
        $mainMarketPlace = $this->marketPlaces[0];
139
        if ($mainMarketPlace) {
140
            $marketPlaceId = $this->countries[$mainMarketPlace];
141
142
            return $this->marketplaceIds[$marketPlaceId];
143
        }
144
145
        throw new CountryIsMissingException();
146
    }
147
148
    public function getCountry()
149
    {
150
        return $this->country;
0 ignored issues
show
Bug introduced by
The property country does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
151
    }
152
153
    public function setCountry($country)
154
    {
155
        if (in_array($country, array_keys($this->countries))) {
156
            $this->country = $country;
157
158
            return $this;
159
        } else {
160
            throw new CountryNotAvailableException();
161
        }
162
    }
163
164
    public function getMarketPlaceIds()
165
    {
166
        return $this->marketplaceIds;
167
    }
168
169
    public function post($action, $path, $version, $params = [], $body = null)
170
    {
171
        $headers = [
172
            'Accept' => 'application/xml',
173
            'x-amazon-user-agent' => self::APPLICATION_NAME.'/'.self::APPLICATION_VERSION,
174
        ];
175
176
        if ($action === 'SubmitFeed') {
177
            $headers['Content-Type'] = 'text/xml; charset=iso-8859-1';
178
        }
179
180
        if ($action === 'GetFeedSubmissionResult') {
181
            $headers['Content-Type'] = 'x-www-form-urlencoded';
182
        }
183
184
        $requestOptions = [
185
            'headers' => $headers,
186
            'body' => $body,
187
            'query' => $this->getQuery($path, $action, $version, $params),
188
        ];
189
        $uri = 'https://'.$this->getDomain().$path;
190
        $response = $this->client->post($uri, $requestOptions);
191
192
        $xmlResponse = simplexml_load_string($response->getBody()->getContents(), 'SimpleXMLElement', LIBXML_NOWARNING | LIBXML_NOERROR);
193
194
        if (! $xmlResponse) {
195
            return (string) $response->getBody();
196
        }
197
198
        $json = json_encode($xmlResponse);
199
200
        return json_decode($json, true);
201
    }
202
203
    public function getDefaultQueryParams($action, $version, $params = [])
204
    {
205
        $queryParameters = [
206
            'Action' => $action,
207
            'Timestamp' => $this->getTimeStamp(),
208
            'AWSAccessKeyId' => $this->getAccessKeyId(),
209
            'SellerId' => $this->getSellerId(),
210
            'MWSAuthToken' => $this->getMWSAuthToken(),
211
            'SignatureMethod' => $this->getSignatureMethod(),
212
            'SignatureVersion' => $this->getSignatureVersion(),
213
            'Version' => $version,
214
        ];
215
        $type = data_get($params, 'FeedType');
216
        $queryParameters = array_merge($queryParameters, $this->getMarketPlaceParams($type));
217
        $queryParameters = array_merge($queryParameters, Arr::dot($params));
0 ignored issues
show
Documentation introduced by
$params is of type array, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
218
        ksort($queryParameters);
219
220
        return $queryParameters;
221
    }
222
223
    public function getMarketPlaceParams($type = null)
224
    {
225
        $params = [];
226
        foreach ($this->marketPlaces as $index => $marketPlace) {
227
            if ($type === '_UPLOAD_VAT_INVOICE_') {
228
                $marketPlaceKeyName = 'MarketplaceIdList.Id.';
229
            } else {
230
                $marketPlaceKeyName = 'MarketplaceId.Id.';
231
            }
232
233
            $keyName = $marketPlaceKeyName.($index + 1);
234
            $params[$keyName] = $this->countries[$marketPlace];
235
        }
236
237
        return $params;
238
    }
239
240
    public function generateRequestUri($action, $version, $params = [])
241
    {
242
        return http_build_query($this->getDefaultQueryParams($action, $version, $params), '', '&', PHP_QUERY_RFC3986);
243
    }
244
245
    public function getQueryStringForSignature($path, $action, $version, $params = [])
246
    {
247
        return  'POST'
248
                    ."\n"
249
                    .$this->getDomain()
250
                    ."\n"
251
                    .$path
252
                    ."\n"
253
                    .$this->generateRequestUri($action, $version, $params);
254
    }
255
256
    public function generateSignature($path, $action, $version, $params = [])
257
    {
258
        $signature = base64_encode(
259
            hash_hmac(
260
                'sha256',
261
                $this->getQueryStringForSignature($path, $action, $version, $params),
262
                $this->secretKey,
263
                true
264
            )
265
        );
266
267
        return $signature;
268
    }
269
270
    public function getQuery($path, $action, $version, $params = [])
271
    {
272
        $queryParameters = $this->getDefaultQueryParams($action, $version, $params);
273
        $queryParameters['Signature'] = $this->generateSignature($path, $action, $version, $params);
274
275
        return $queryParameters;
276
    }
277
}
278