Completed
Push — master ( ba6a5c...060d7c )
by ARCANEDEV
12s
created

StripeResource   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 415
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 97.09%

Importance

Changes 0
Metric Value
dl 0
loc 415
ccs 100
cts 103
cp 0.9709
rs 9.6
c 0
b 0
f 0
wmc 32
lcom 1
cbo 9

20 Methods

Rating   Name   Duplication   Size   Complexity  
A scopedRetrieve() 0 10 1
A scopedAll() 0 18 1
A scopedCreate() 0 12 1
A scopedUpdate() 0 12 1
A scopedSave() 0 10 2
A scopedDelete() 0 9 1
A classUrl() 0 6 1
A instanceUrl() 0 4 1
A resourceUrl() 0 11 2
A request() 0 10 1
A staticRequest() 0 15 3
A baseUrl() 0 4 1
A refresh() 0 11 1
A className() 0 7 1
A getShortNameClass() 0 7 2
A scopedPostCall() 0 11 1
A checkArguments() 0 5 1
A checkParameters() 0 10 3
B checkOptions() 0 16 5
A checkIsCollectionObject() 0 8 2
1
<?php namespace Arcanedev\Stripe;
2
3
use Arcanedev\Stripe\Contracts\StripeResource as StripeResourceContract;
4
use Arcanedev\Stripe\Http\RequestOptions;
5
use Arcanedev\Stripe\Http\Requestor;
6
use Arcanedev\Stripe\Utilities\Util;
7
use ReflectionClass;
8
9
/**
10
 * Class     StripeResource
11
 *
12
 * @package  Arcanedev\Stripe
13
 * @author   ARCANEDEV <[email protected]>
14
 */
15
abstract class StripeResource extends StripeObject implements StripeResourceContract
16
{
17
    /* -----------------------------------------------------------------
18
     |  Properties
19
     | -----------------------------------------------------------------
20
     */
21
22
    /** @var array */
23
    private static $persistedHeaders = [
24
        'Stripe-Account' => true,
25
        'Stripe-Version' => true,
26
    ];
27
28
    /* -----------------------------------------------------------------
29
     |  Main Methods
30
     | -----------------------------------------------------------------
31
     */
32
33
    /**
34
     * Get the base url.
35
     *
36
     * @return string
37
     */
38 534
    public static function baseUrl()
39 6
    {
40 534
        return Stripe::getApiBaseUrl();
41
    }
42
43
    /**
44
     * Get the refreshed resource.
45
     *
46
     * @return self
47
     */
48 267
    public function refresh()
49 2
    {
50 267
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
51 267
            ->get($this->instanceUrl(), $this->retrieveParameters, $this->opts->headers);
52
53
        /** @var \Arcanedev\Stripe\Http\Response $response */
54 228
        $this->setLastResponse($response);
55 228
        $this->refreshFrom($response->getJson(), $this->opts);
56
57 233
        return $this;
58
    }
59
60
    /**
61
     * Get The name of the class, with namespacing and underscores stripped.
62
     *
63
     * @param  string  $class
64
     *
65
     * @return string
66
     */
67 507
    public static function className($class = '')
68
    {
69 507
        $name = self::getShortNameClass($class);
70 507
        $name = str_split_camelcase($name, '_');
71
72 507
        return strtolower(urlencode($name));
73
    }
74
75
    /**
76
     * Get Class short name.
77
     *
78
     * @param  string  $class
79
     *
80
     * @return string
81
     */
82 507
    protected static function getShortNameClass($class = '')
83
    {
84 507
        if (empty($class))
85 499
            $class = get_called_class();
86
87 507
        return (new ReflectionClass($class))->getShortName();
88
    }
89
90
    /**
91
     * Get the endpoint URL for the given class.
92
     *
93
     * @param  string  $class
94
     *
95
     * @return string
96
     */
97 498
    public static function classUrl($class = '')
98
    {
99 498
        $base = self::className($class);
100
101 498
        return "/v1/${base}s";
102
    }
103
104
    /**
105
     * Get Instance URL.
106
     *
107
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
108
     *
109
     * @return string
110
     */
111
    public function instanceUrl()
112
    {
113 342
        return static::resourceUrl($this['id']);
114
    }
115
116
    /**
117
     * Get the instance endpoint URL for the given class.
118
     *
119
     * @param  string  $id
120
     *
121
     * @return string
122
     *
123
     * @throws Exceptions\InvalidRequestException
124
     */
125
    public static function resourceUrl($id)
126
    {
127 360
        if ($id === null) {
128 9
            $class = get_called_class();
129 9
            throw new Exceptions\InvalidRequestException(
130 9
                "Could not determine which URL to request: $class instance has invalid ID: $id", null
131 3
            );
132
        }
133
134 351
        return static::classUrl().'/'.urlencode(str_utf8($id));
135
    }
136
137
    /* ------------------------------------------------------------------------------------------------
138
     |  Request Functions
139
     | ------------------------------------------------------------------------------------------------
140
     */
141
    /**
142
     * Make a request.
143
     *
144
     * @param  string             $method
145
     * @param  string             $url
146
     * @param  array|null         $params
147
     * @param  array|string|null  $options
148
     *
149
     * @return array
150
     */
151
    protected function request($method, $url, $params = [], $options = null)
152
    {
153 219
        $opts = $this->opts->merge($options);
154
155
        /** @var \Arcanedev\Stripe\Http\Response $response */
156 219
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
157 219
        $this->setLastResponse($response);
158
159 219
        return [$response->getJson(), $options];
160
    }
161
162
    /**
163
     * Make a request (static).
164
     *
165
     * @param  string             $method
166
     * @param  string             $url
167
     * @param  array|null         $params
168
     * @param  array|string|null  $options
169
     *
170
     * @return array
171
     */
172
    protected static function staticRequest($method, $url, $params, $options)
173
    {
174 504
        $opts      = RequestOptions::parse($options);
175 504
        $requestor = Requestor::make($opts->apiKey, static::baseUrl());
176
177 492
        list($response, $opts->apiKey) =
178 504
            $requestor->request($method, $url, $params, $opts->headers);
179
180 492
        foreach ($opts->headers as $k => $v) {
181 30
            if ( ! array_key_exists($k, self::$persistedHeaders))
182 21
                unset($opts->headers[$k]);
183 164
        }
184
185 492
        return [$response, $opts];
186
    }
187
188
    /* -----------------------------------------------------------------
189
     |  CRUD Scope Methods
190
     | -----------------------------------------------------------------
191
     */
192
193
    /**
194
     * Retrieve scope.
195
     *
196
     * @param  string             $id
197
     * @param  array|string|null  $options
198
     *
199
     * @return self
200
     */
201
    protected static function scopedRetrieve($id, $options = null)
202
    {
203 261
        $class = get_called_class();
204
205
        /** @var self $resource */
206 261
        $resource = new $class($id, RequestOptions::parse($options));
207 261
        $resource->refresh();
208
209 222
        return $resource;
210
    }
211
212
    /**
213
     * List scope.
214
     *
215
     * @param  array|null         $params
216
     * @param  array|string|null  $options
217
     *
218
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
219
     *
220
     * @return \Arcanedev\Stripe\Collection|array
221
     */
222
    protected static function scopedAll($params = [], $options = null)
223
    {
224 91
        self::checkArguments($params, $options);
225
226 84
        $url = static::classUrl();
227
228
        /** @var \Arcanedev\Stripe\Http\Response $response */
229 84
        list($response, $opts) = self::staticRequest('get', $url, $params, $options);
230
231 84
        $object = Util::convertToStripeObject($response->getJson(), $opts);
232
233 84
        self::checkIsCollectionObject($object);
234
235 84
        $object->setLastResponse($response);
236 84
        $object->setRequestParams($params);
237
238 84
        return $object;
239
    }
240
241
    /**
242
     * Create scope.
243
     *
244
     * @param  array|null         $params
245
     * @param  array|string|null  $options
246
     *
247
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
248
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
249
     *
250
     * @return self
251
     */
252
    protected static function scopedCreate($params = [], $options = null)
253
    {
254 423
        self::checkArguments($params, $options);
255
256
        /** @var \Arcanedev\Stripe\Http\Response $response */
257 423
        list($response, $opts) = static::staticRequest('post', static::classUrl(), $params, $options);
258
259 411
        $object = Util::convertToStripeObject($response->getJson(), $opts);
0 ignored issues
show
Bug Compatibility introduced by
The expression \Arcanedev\Stripe\Utilit...nse->getJson(), $opts); of type array|Arcanedev\Stripe\StripeObject adds the type array to the return on line 262 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedCreate of type Arcanedev\Stripe\StripeResource.
Loading history...
260 411
        $object->setLastResponse($response);
261
262 411
        return $object;
263
    }
264
265
    /**
266
     * Update scope.
267
     *
268
     * @param  string             $id
269
     * @param  array|null         $params
270
     * @param  array|string|null  $options
271
     *
272
     * @return self
273
     *
274
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
275
     */
276
    protected static function scopedUpdate($id, $params = null, $options = null)
277
    {
278 48
        self::checkArguments($params, $options);
279
280
        /** @var \Arcanedev\Stripe\Http\Response $response */
281 48
        list($response, $opts) = static::staticRequest('post', static::resourceUrl($id), $params, $options);
282
283 48
        $object = Util::convertToStripeObject($response->getJson(), $opts);
0 ignored issues
show
Bug Compatibility introduced by
The expression \Arcanedev\Stripe\Utilit...nse->getJson(), $opts); of type array|Arcanedev\Stripe\StripeObject adds the type array to the return on line 286 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedUpdate of type Arcanedev\Stripe\StripeResource.
Loading history...
Bug introduced by
It seems like $response->getJson() targeting Arcanedev\Stripe\Http\Response::getJson() can also be of type null; however, Arcanedev\Stripe\Utiliti...convertToStripeObject() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
284 48
        $object->setLastResponse($response);
285
286 48
        return $object;
287
    }
288
289
    /**
290
     * Save scope.
291
     *
292
     * @param  array|string|null  $options
293
     *
294
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
295
     *
296
     * @return self
297
     */
298
    protected function scopedSave($options = null)
299
    {
300 129
        if (count($params = $this->serializeParameters()) > 0) {
301 108
            self::checkArguments(null, $options);
302 108
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
303 108
            $this->refreshFrom($response, $opts);
304 36
        }
305
306 129
        return $this;
307
    }
308
309
    /**
310
     * Delete Scope.
311
     *
312
     * @param  array|null         $params
313
     * @param  array|string|null  $options
314
     *
315
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
316
     *
317
     * @return self
318
     */
319
    protected function scopedDelete($params = [], $options = null)
320
    {
321 45
        self::checkArguments($params, $options);
322
323 45
        list($response, $opts) = $this->request('delete', $this->instanceUrl(), $params, $options);
324 45
        $this->refreshFrom($response, $opts);
325
326 45
        return $this;
327
    }
328
329
    /* -----------------------------------------------------------------
330
     |  Custom Scope Methods
331
     | -----------------------------------------------------------------
332
     */
333
334
    /**
335
     * Custom Post Call.
336
     *
337
     * @param  string             $url
338
     * @param  array|null         $params
339
     * @param  array|string|null  $options
340
     *
341
     * @return self
342
     */
343
    protected function scopedPostCall($url, $params = [], $options = null)
344
    {
345
        /** @var \Arcanedev\Stripe\Http\Response $response */
346 27
        list($response, $options) = Requestor::make(RequestOptions::parse($options)->getApiKey(), static::baseUrl())
347 27
            ->post($url, $params);
348
349 27
        $this->refreshFrom($response->getJson(), $options);
350 27
        $this->setLastResponse($response);
351
352 27
        return $this;
353
    }
354
355
    /* -----------------------------------------------------------------
356
     |  Check Methods
357
     | -----------------------------------------------------------------
358
     */
359
360
    /**
361
     * Check Arguments.
362
     *
363
     * @param  array|null         $params
364
     * @param  array|string|null  $options
365
     */
366
    protected static function checkArguments($params = [], $options = null)
367
    {
368 501
        self::checkParameters($params);
369 498
        self::checkOptions($options);
370 495
    }
371
372
    /**
373
     * Check parameters.
374
     *
375
     * @param  array|null  $params
376
     *
377
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
378
     */
379
    private static function checkParameters($params)
380
    {
381 501
        if ($params && ! is_array($params)) {
382 3
            throw new Exceptions\InvalidArgumentException(
383
                'You must pass an array as the first argument to Stripe API method calls.  '.
384 1
                '(HINT: an example call to create a charge would be: '.
385 2
                "StripeCharge::create(['amount' => 100, 'currency' => 'usd', 'source' => 'tok_1234']))"
386 1
            );
387
        }
388 498
    }
389
390
    /**
391
     * Check Options.
392
     *
393
     * @param  array|string|null  $options
394
     *
395
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
396
     */
397
    private static function checkOptions($options)
398
    {
399 498
        if ($options && (
400 45
                ! $options instanceof RequestOptions &&
401 41
                ! is_string($options) &&
402 188
                ! is_array($options)
403 11
            )
404 166
        ) {
405 3
            throw new Exceptions\ApiException(
406
                'The second argument to Stripe API method calls is an '
407
                . 'optional per-request apiKey, which must be a string.  '
408 3
                . '(HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")',
409 98
                500
410 1
            );
411
        }
412 495
    }
413
414
    /**
415
     * Check the object is a Collection class.
416
     *
417
     * @param  mixed  $object
418
     *
419
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
420
     */
421
    private static function checkIsCollectionObject($object)
422
    {
423 84
        if ( ! is_a($object, Collection::class)) {
424
            throw new Exceptions\ApiException(
425
                'Expected type "Arcanedev\Stripe\Collection", got "'.get_class($object).'" instead'
426
            );
427
        }
428 84
    }
429
}
430