Completed
Push — master ( 2236d8...f66191 )
by Taosikai
10:51
created

Client::getHydrator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the slince/shopify-api-php
5
 *
6
 * (c) Slince <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Slince\Shopify;
13
14
use Doctrine\Common\Inflector\Inflector;
15
use GuzzleHttp\Psr7\Request;
16
use Slince\Di\Container;
17
use GuzzleHttp\Client as HttpClient;
18
use Psr\Http\Message\RequestInterface;
19
use Psr\Http\Message\ResponseInterface;
20
use Slince\Shopify\Exception\InvalidArgumentException;
21
use GuzzleHttp\Exception\RequestException;
22
use Slince\Shopify\Exception\ClientException;
23
use Slince\Shopify\Hydrator\Hydrator;
24
25
/**
26
 * @method Manager\Article\ArticleManagerInterface getArticleManager
27
 * @method Manager\Asset\AssetManagerInterface getAssetManager
28
 * @method Manager\Blog\BlogManagerInterface getBlogManager
29
 * @method Manager\CarrierService\CarrierServiceManagerInterface getCarrierServiceManager
30
 * @method Manager\Collect\CollectManagerInterface getCollectManager
31
 * @method Manager\Comment\CommentManagerInterface getCommentManager
32
 * @method Manager\Country\CountryManagerInterface getCountryManager
33
 * @method Manager\CustomCollection\CustomCollectionManagerInterface getCustomCollectionManager
34
 * @method Manager\Customer\CustomerManagerInterface getCustomerManager
35
 * @method Manager\CustomerAddress\AddressManagerInterface getCustomerAddressManager
36
 * @method Manager\CustomerSavedSearch\CustomerSavedSearchManagerInterface getCustomerSavedSearchManager
37
 * @method Manager\Fulfillment\FulfillmentManagerInterface getFulfillmentManager
38
 * @method Manager\FulfillmentService\FulfillmentServiceManagerInterface getFulfillmentServiceManager
39
 * @method Manager\Order\OrderManagerInterface getOrderManager
40
 * @method Manager\OrderRisk\RiskManagerInterface getOrderRiskManager
41
 * @method Manager\Page\PageManagerInterface getPageManager
42
 * @method Manager\Policy\PolicyManagerInterface getPolicyManager
43
 * @method Manager\Product\ProductManagerInterface getProductManager
44
 * @method Manager\ProductImage\ImageManagerInterface getProductImageManager
45
 * @method Manager\ProductVariant\VariantManagerInterface getProductVariantManager
46
 * @method Manager\Province\ProvinceManagerInterface getProvinceManager
47
 * @method Manager\Redirect\RedirectManagerInterface getRedirectManager
48
 * @method Manager\Refund\RefundManagerInterface getRefundManager
49
 * @method Manager\ShippingZone\ShippingZoneManagerInterface getShippingZoneManager
50
 * @method Manager\Shop\ShopManagerInterface getShopManager
51
 * @method Manager\Theme\ThemeManagerInterface getThemeManager
52
 * @method Manager\Transaction\TransactionManagerInterface getTransactionManager
53
 * @method Manager\Webhook\WebhookManagerInterface getWebhookManager
54
 */
55
class Client
56
{
57
    /**
58
     * @var HttpClient
59
     */
60
    protected $httpClient;
61
62
    /**
63
     * @var Container
64
     */
65
    protected $container;
66
67
    /**
68
     * @var CredentialInterface
69
     */
70
    protected $credential;
71
72
    /**
73
     * The shop.
74
     *
75
     * @var string
76
     */
77
    protected $shop;
78
79
    /**
80
     * Array of services classes.
81
     *
82
     * @var array
83
     */
84
    public $serviceClass = [
85
        Manager\Article\ArticleManager::class,
86
        Manager\Asset\AssetManager::class,
87
        Manager\Blog\BlogManager::class,
88
        Manager\CarrierService\CarrierServiceManager::class,
89
        Manager\Collect\CollectManager::class,
90
        Manager\Comment\CommentManager::class,
91
        Manager\Country\CountryManager::class,
92
        Manager\CustomCollection\CustomCollectionManager::class,
93
        Manager\Customer\CustomerManager::class,
94
        Manager\CustomerAddress\AddressManager::class,
95
        Manager\CustomerSavedSearch\CustomerSavedSearchManager::class,
96
        Manager\Fulfillment\FulfillmentManager::class,
97
        Manager\FulfillmentService\FulfillmentServiceManager::class,
98
        Manager\Location\LocationManager::class,
99
        Manager\Order\OrderManager::class,
100
        Manager\OrderRisk\RiskManager::class,
101
        Manager\Page\PageManager::class,
102
        Manager\Policy\PolicyManager::class,
103
        Manager\Product\ProductManager::class,
104
        Manager\ProductImage\ImageManager::class,
105
        Manager\ProductVariant\VariantManager::class,
106
        Manager\Province\ProvinceManager::class,
107
        Manager\Redirect\RedirectManager::class,
108
        Manager\Refund\RefundManager::class,
109
        Manager\ShippingZone\ShippingZoneManager::class,
110
        Manager\Shop\ShopManager::class,
111
        Manager\Theme\ThemeManager::class,
112
        Manager\Transaction\TransactionManager::class,
113
        Manager\Webhook\WebhookManager::class,
114
    ];
115
116
    /**
117
     * Whether depay the next request.
118
     *
119
     * @var bool
120
     */
121
    protected static $delayNextRequest = false;
122
123
    /**
124
     * @var string
125
     */
126
    protected $metaCacheDir;
127
128
    /**
129
     * @var Hydrator
130
     */
131
    protected $hydrator;
132
133
    public function __construct(CredentialInterface $credential, $shop, array $options = [])
134
    {
135
        $this->container = new Container();
136
        $this->container->instance($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Slince\Shopify\Client>, but the function expects a string.

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...
137
        $this->credential = $credential;
138
        $this->setShop($shop);
139
        $this->applyOptions($options);
140
        $this->hydrator = new Hydrator($this->metaCacheDir, __DIR__ . '/../config/serializer');
141
        $this->initializeBaseServices();
142
    }
143
144
    public function __call($name, $arguments)
145
    {
146
        if ('Manager' === substr($name, -7)) {
147
            $serviceName = substr($name, 3, -7);
148
149
            return $this->container->get(Inflector::tableize(Inflector::pluralize($serviceName)));
150
        }
151
        throw new \InvalidArgumentException(sprintf('The method "%s" is not exists', $name));
152
    }
153
154
    /**
155
     * Gets the credential.
156
     *
157
     * @return CredentialInterface
158
     */
159
    public function getCredential()
160
    {
161
        return $this->credential;
162
    }
163
164
    /**
165
     * sets the shop name for the client.
166
     *
167
     * @param string $shop
168
     */
169
    public function setShop($shop)
170
    {
171
        if (!preg_match('/^[a-zA-Z0-9\-]{3,100}\.myshopify\.(?:com|io)$/', $shop)) {
172
            throw new InvalidArgumentException(
173
                'Shop name should be 3-100 letters, numbers, or hyphens e.g. your-store.myshopify.com'
174
            );
175
        }
176
        $this->shop = $shop;
177
    }
178
179
    /**
180
     * Gets the shop.
181
     *
182
     * @return string
183
     */
184
    public function getShop()
185
    {
186
        return $this->shop;
187
    }
188
189
    /**
190
     * Sets the http client for the client.
191
     *
192
     * @param HttpClient $httpClient
193
     */
194
    public function setHttpClient($httpClient)
195
    {
196
        $this->httpClient = $httpClient;
197
    }
198
199
    /**
200
     * Gets the http client.
201
     *
202
     * @return HttpClient
203
     */
204
    public function getHttpClient()
205
    {
206
        return $this->httpClient ?: new HttpClient([
207
            'verify' => false,
208
        ]);
209
    }
210
211
    /**
212
     * Perform a GET request.
213
     *
214
     * @param string $resource
215
     * @param array  $query
216
     *
217
     * @return array
218
     */
219
    public function get($resource, $query = [])
220
    {
221
        return $this->doRequest('GET', $resource, [
222
            'query' => $query,
223
        ]);
224
    }
225
226
    /**
227
     * Perform a POST request.
228
     *
229
     * @param string $resource
230
     * @param array  $data
231
     * @param array  $query
232
     *
233
     * @return array
234
     */
235
    public function post($resource, $data, $query = [])
236
    {
237
        return $this->doRequest('POST', $resource, [
238
            'query' => $query,
239
            'json' => $data,
240
        ]);
241
    }
242
243
    /**
244
     * Perform a PUT request.
245
     *
246
     * @param string $resource
247
     * @param array  $data
248
     * @param array  $query
249
     *
250
     * @return array
251
     */
252
    public function put($resource, $data, $query = [])
253
    {
254
        return $this->doRequest('PUT', $resource, [
255
            'query' => $query,
256
            'json' => $data,
257
        ]);
258
    }
259
260
    /**
261
     * Perform a DELETE request.
262
     *
263
     * @param string $resource
264
     */
265
    public function delete($resource)
266
    {
267
        $this->doRequest('DELETE', $resource);
268
    }
269
270
    protected function doRequest($method, $resource, $options = [])
271
    {
272
        $request = new Request($method, $this->buildUrl($resource));
273
        $response = $this->sendRequest($request, $options);
274
275
        return \GuzzleHttp\json_decode($response->getBody(), true);
276
    }
277
278
    /**
279
     * Builds an url by given resource name.
280
     *
281
     * @param string $resource
282
     *
283
     * @return string
284
     */
285
    protected function buildUrl($resource)
286
    {
287
        return sprintf('https://%s/admin/%s.json', $this->shop, $resource);
288
    }
289
290
    /**
291
     * Send a request.
292
     *
293
     * @param RequestInterface $request
294
     * @param array            $options
295
     *
296
     * @return ResponseInterface
297
     * @codeCoverageIgnore
298
     */
299
    public function sendRequest(RequestInterface $request, array $options = [])
300
    {
301
        $request = $request->withHeader('Content-Type', 'application/json');
302
        $request = $this->credential->applyToRequest($request);
303
        if (static::$delayNextRequest) {
304
            usleep(100 * rand(1, 10));
305
        }
306
        try {
307
            $response = $this->getHttpClient()->send($request, $options);
308
        } catch (RequestException $exception) {
309
            $exception = new ClientException($request, $exception->getResponse(), $exception->getMessage());
310
            throw $exception;
311
        }
312
        list($callsMade, $callsLimit) = explode('/', $response->getHeaderLine('http_x_shopify_shop_api_call_limit'));
313
        static::$delayNextRequest = $callsMade / $callsLimit >= 0.8;
314
315
        return $response;
316
    }
317
318
    /**
319
     * Applies the array of request options to the client.
320
     *
321
     * @param array $options
322
     */
323
    protected function applyOptions(array $options)
324
    {
325
        isset($options['httpClient']) && $this->httpClient = $options['httpClient'];
326
        if (!isset($options['metaCacheDir'])) {
327
            throw new InvalidArgumentException('You must provide option "metaCacheDir"');
328
        }
329
        $this->metaCacheDir = $options['metaCacheDir'];
330
    }
331
332
    /**
333
     * Gets the hydrator instance
334
     *
335
     * @return Hydrator
336
     */
337
    public function getHydrator()
338
    {
339
        return $this->hydrator;
340
    }
341
342
    /**
343
     * Initialize base services.
344
     */
345
    protected function initializeBaseServices()
346
    {
347
        foreach ($this->serviceClass as $serviceClass) {
348
            $this->container->define($serviceClass::getServiceName(), $serviceClass);
349
        }
350
    }
351
}