Completed
Pull Request — master (#47)
by ARCANEDEV
08:31
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.12%

Importance

Changes 0
Metric Value
dl 0
loc 418
ccs 101
cts 104
cp 0.9712
rs 9.6
c 0
b 0
f 0
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
A checkIsCollectionObject() 0 8 2
B checkOptions() 0 16 5
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
    /** @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 340
    public static function baseUrl()
37
    {
38 340
        return Stripe::getApiBaseUrl();
39 4
    }
40
41
    /**
42
     * Get the refreshed resource.
43
     *
44
     * @return self
45
     */
46 152
    public function refresh()
47
    {
48 152
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
49 152
            ->get($this->instanceUrl(), $this->retrieveParameters);
50
51
52
        /** @var \Arcanedev\Stripe\Http\Response $response */
53 131
        $this->setLastResponse($response);
54 126
        $this->refreshFrom($response->getJson(), $this->opts);
55
56 126
        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 322
    public static function className($class = '')
67
    {
68 322
        $name = self::getShortNameClass($class);
69 322
        $name = str_split_camelcase($name, '_');
70
71 322
        return strtolower(urlencode($name));
72
    }
73
74
    /**
75
     * Get Class short name.
76
     *
77
     * @param  string  $class
78
     *
79
     * @return string
80
     */
81 322
    protected static function getShortNameClass($class = '')
82
    {
83 322
        if (empty($class))
84 318
            $class = get_called_class();
85
86 322
        $class = new ReflectionClass($class);
87
88 322
        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 316
    public static function classUrl($class = '')
99
    {
100 316
        $base = self::className($class);
101
102 316
        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 202
        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 214
        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 208
        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 126
        $opts = $this->opts->merge($options);
155
156
        /** @var \Arcanedev\Stripe\Http\Response $response */
157 126
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
158 126
        $this->setLastResponse($response);
159
160 126
        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 322
        $opts      = RequestOptions::parse($options);
176 322
        $requestor = Requestor::make($opts->apiKey, static::baseUrl());
177
178 314
        list($response, $opts->apiKey) =
179 322
            $requestor->request($method, $url, $params, $opts->headers);
180
181 314
        foreach ($opts->headers as $k => $v) {
182 2
            if ( ! array_key_exists($k, self::$persistedHeaders))
183 2
                unset($opts->headers[$k]);
184 157
        }
185
186 314
        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 148
        $class    = get_called_class();
204
205
        /** @var self $resource */
206 148
        $resource = new $class($id, RequestOptions::parse($options));
207 148
        $resource->refresh();
208
209 122
        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 63
        self::checkArguments($params, $options);
225
226 58
        $url = static::classUrl();
227
228
        /** @var \Arcanedev\Stripe\Http\Response $response */
229 58
        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 32
        $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 32
        $object->setLastResponse($response);
285
286 32
        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 70
        if (count($params = $this->serializeParameters()) > 0) {
301 62
            self::checkArguments(null, $options);
302 62
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
303 62
            $this->refreshFrom($response, $opts);
304 31
        }
305
306 70
        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 28
        self::checkArguments($params, $options);
322
323 28
        list($response, $opts) = $this->request('delete', $this->instanceUrl(), $params, $options);
324 28
        $this->refreshFrom($response, $opts);
325
326 28
        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 320
        self::checkParameters($params);
371 318
        self::checkOptions($options);
372 316
    }
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 320
        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 318
    }
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 318
        if ($options && (
403 14
                ! $options instanceof RequestOptions &&
404 14
                ! is_string($options) &&
405 161
                ! is_array($options)
406 2
            )
407 159
        ) {
408 2
            throw new Exceptions\ApiException(
409 83
                '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 316
    }
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