Completed
Push — master ( d70789...03a9c1 )
by ARCANEDEV
12s
created

StripeResource   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 97.09%

Importance

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

20 Methods

Rating   Name   Duplication   Size   Complexity  
A baseUrl() 0 4 1
A refresh() 0 12 1
A className() 0 7 1
A getShortNameClass() 0 9 2
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 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 scopedPostCall() 0 11 1
A checkArguments() 0 5 1
A checkParameters() 0 11 3
B checkOptions() 0 16 5
A checkIsCollectionObject() 0 8 2
1
<?php namespace Arcanedev\Stripe;
2
3
use Arcanedev\Stripe\Contracts\StripeResourceInterface;
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 StripeResourceInterface
16
{
17
    /* ------------------------------------------------------------------------------------------------
18
     |  Properties
19
     | ------------------------------------------------------------------------------------------------
20
     */
21
    /** @var array */
22
    private static $persistedHeaders = [
23
        'Stripe-Account' => true,
24
        'Stripe-Version' => true,
25
    ];
26
27
    /* ------------------------------------------------------------------------------------------------
28
     |  Main Functions
29
     | ------------------------------------------------------------------------------------------------
30
     */
31
    /**
32
     * Get the base url.
33
     *
34
     * @return string
35
     */
36 332
    public static function baseUrl()
37
    {
38 332
        return Stripe::getApiBaseUrl();
39 4
    }
40
41
    /**
42
     * Get the refreshed resource.
43
     *
44
     * @return self
45
     */
46 156
    public function refresh()
47
    {
48 156
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
49 156
            ->get($this->instanceUrl(), $this->retrieveParameters);
50
51
52
        /** @var \Arcanedev\Stripe\Http\Response $response */
53 133
        $this->setLastResponse($response);
54 128
        $this->refreshFrom($response->getJson(), $this->opts);
55
56 128
        return $this;
57
    }
58
59
    /**
60
     * Get The name of the class, with namespacing and underscores stripped.
61
     *
62
     * @param  string  $class
63
     *
64
     * @return string
65
     */
66 314
    public static function className($class = '')
67
    {
68 314
        $name = self::getShortNameClass($class);
69 314
        $name = str_split_camelcase($name, '_');
70
71 314
        return strtolower(urlencode($name));
72
    }
73
74
    /**
75
     * Get Class short name.
76
     *
77
     * @param  string  $class
78
     *
79
     * @return string
80
     */
81 314
    protected static function getShortNameClass($class = '')
82
    {
83 314
        if (empty($class))
84 310
            $class = get_called_class();
85
86 314
        $class = new ReflectionClass($class);
87
88 314
        return $class->getShortName();
89
    }
90
91
    /**
92
     * Get the endpoint URL for the given class.
93
     *
94
     * @param  string  $class
95
     *
96
     * @return string
97
     */
98 308
    public static function classUrl($class = '')
99
    {
100 308
        $base = self::className($class);
101
102 308
        return "/v1/${base}s";
103
    }
104
105
    /**
106
     * Get Instance URL.
107
     *
108
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
109
     *
110
     * @return string
111
     */
112
    public function instanceUrl()
113
    {
114 206
        return static::resourceUrl($this['id']);
115
    }
116
117
    /**
118
     * Get the instance endpoint URL for the given class.
119
     *
120
     * @param  string  $id
121
     *
122
     * @return string
123
     *
124
     * @throws Exceptions\InvalidRequestException
125
     */
126
    public static function resourceUrl($id)
127
    {
128 218
        if ($id === null) {
129 6
            $class = get_called_class();
130 6
            throw new Exceptions\InvalidRequestException(
131 6
                "Could not determine which URL to request: $class instance has invalid ID: $id", null
132 3
            );
133
        }
134
135 212
        return static::classUrl().'/'.urlencode(str_utf8($id));
136
    }
137
138
    /* ------------------------------------------------------------------------------------------------
139
     |  Request Functions
140
     | ------------------------------------------------------------------------------------------------
141
     */
142
    /**
143
     * Make a request.
144
     *
145
     * @param  string             $method
146
     * @param  string             $url
147
     * @param  array|null         $params
148
     * @param  array|string|null  $options
149
     *
150
     * @return array
151
     */
152
    protected function request($method, $url, $params = [], $options = null)
153
    {
154 124
        $opts = $this->opts->merge($options);
155
156
        /** @var \Arcanedev\Stripe\Http\Response $response */
157 124
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
158 124
        $this->setLastResponse($response);
159
160 124
        return [$response->getJson(), $options];
161
    }
162
163
    /**
164
     * Make a request (static).
165
     *
166
     * @param  string             $method
167
     * @param  string             $url
168
     * @param  array|null         $params
169
     * @param  array|string|null  $options
170
     *
171
     * @return array
172
     */
173
    protected static function staticRequest($method, $url, $params, $options)
174
    {
175 316
        $opts      = RequestOptions::parse($options);
176 316
        $requestor = Requestor::make($opts->apiKey, static::baseUrl());
177
178 308
        list($response, $opts->apiKey) =
179 316
            $requestor->request($method, $url, $params, $opts->headers);
180
181 308
        foreach ($opts->headers as $k => $v) {
182 2
            if ( ! array_key_exists($k, self::$persistedHeaders))
183 2
                unset($opts->headers[$k]);
184 154
        }
185
186 308
        return [$response, $opts];
187
    }
188
189
    /* ------------------------------------------------------------------------------------------------
190
     |  CRUD Scope Functions
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 152
        $class    = get_called_class();
204
205
        /** @var self $resource */
206 152
        $resource = new $class($id, RequestOptions::parse($options));
207 152
        $resource->refresh();
208
209 124
        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 60
        self::checkArguments($params, $options);
225
226 56
        $url = static::classUrl();
227
228
        /** @var \Arcanedev\Stripe\Http\Response $response */
229 56
        list($response, $opts) = self::staticRequest('get', $url, $params, $options);
230
231 56
        $object = Util::convertToStripeObject($response->getJson(), $opts);
232
233 56
        self::checkIsCollectionObject($object);
234
235 56
        $object->setLastResponse($response);
236 56
        $object->setRequestParams($params);
237
238 56
        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 272
        self::checkArguments($params, $options);
255
256
        /** @var \Arcanedev\Stripe\Http\Response $response */
257 272
        list($response, $opts) = static::staticRequest('post', static::classUrl(), $params, $options);
258
259 264
        $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 264
        $object->setLastResponse($response);
261
262 264
        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 32
        self::checkArguments($params, $options);
279
280
        /** @var \Arcanedev\Stripe\Http\Response $response */
281 32
        list($response, $opts) = static::staticRequest('post', static::resourceUrl($id), $params, $options);
282
283 30
        $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 30
        $object->setLastResponse($response);
285
286 30
        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 68
        if (count($params = $this->serializeParameters()) > 0) {
301 60
            self::checkArguments(null, $options);
302 60
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
303 60
            $this->refreshFrom($response, $opts);
304 30
        }
305
306 68
        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 26
        self::checkArguments($params, $options);
322
323 26
        list($response, $opts) = $this->request('delete', $this->instanceUrl(), $params, $options);
324 26
        $this->refreshFrom($response, $opts);
325
326 26
        return $this;
327
    }
328
329
    /* ------------------------------------------------------------------------------------------------
330
     |  Custom Scope Functions
331
     | ------------------------------------------------------------------------------------------------
332
     */
333
    /**
334
     * Custom Post Call.
335
     *
336
     * @param  string             $url
337
     * @param  array|null         $params
338
     * @param  array|string|null  $options
339
     *
340
     * @return self
341
     */
342
    protected function scopedPostCall($url, $params = [], $options = null)
343
    {
344
        /** @var \Arcanedev\Stripe\Http\Response $response */
345 18
        list($response, $options) = Requestor::make(RequestOptions::parse($options)->getApiKey(), static::baseUrl())
346 18
            ->post($url, $params);
347
348 18
        $this->refreshFrom($response->getJson(), $options);
349 18
        $this->setLastResponse($response);
350
351 18
        return $this;
352
    }
353
354
    /* ------------------------------------------------------------------------------------------------
355
     |  Check Functions
356
     | ------------------------------------------------------------------------------------------------
357
     */
358
    /**
359
     * Check Arguments.
360
     *
361
     * @param  array|null         $params
362
     * @param  array|string|null  $options
363
     *
364
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
365
     * @throws \Arcanedev\Stripe\Exceptions\BadMethodCallException
366
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
367
     */
368
    private static function checkArguments($params = [], $options = null)
369
    {
370 316
        self::checkParameters($params);
371 314
        self::checkOptions($options);
372 312
    }
373
374
    /**
375
     * Check parameters.
376
     *
377
     * @param  array|null  $params
378
     *
379
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
380
     */
381
    private static function checkParameters($params)
382
    {
383 316
        if ($params && ! is_array($params)) {
384 2
            throw new Exceptions\InvalidArgumentException(
385
                'You must pass an array as the first argument to Stripe API method calls.  '
386
                . '(HINT: an example call to create a charge would be: '
387 1
                . 'StripeCharge::create([\'amount\' => 100, \'currency\' => \'usd\', '
388 1
                . '\'card\' => [\'number\' => 4242424242424242, \'exp_month\' => 5, '
389 2
                . '\'exp_year\' => 2015]]))');
390
        }
391 314
    }
392
393
    /**
394
     * Check Options.
395
     *
396
     * @param  array|string|null  $options
397
     *
398
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
399
     */
400
    private static function checkOptions($options)
401
    {
402 314
        if ($options && (
403 14
                ! $options instanceof RequestOptions &&
404 14
                ! is_string($options) &&
405 159
                ! is_array($options)
406 2
            )
407 157
        ) {
408 86
            throw new Exceptions\ApiException(
409
                'The second argument to Stripe API method calls is an '
410
                . 'optional per-request apiKey, which must be a string.  '
411 2
                . '(HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")',
412 1
                500
413 1
            );
414
        }
415 312
    }
416
417
    /**
418
     * Check the object is a Collection class.
419
     *
420
     * @param  mixed  $object
421
     *
422
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
423
     */
424
    private static function checkIsCollectionObject($object)
425
    {
426 56
        if ( ! is_a($object, Collection::class)) {
427
            throw new Exceptions\ApiException(
428
                'Expected type "Arcanedev\Stripe\Collection", got "'.get_class($object).'" instead'
429
            );
430
        }
431 56
    }
432
}
433