Completed
Pull Request — master (#47)
by ARCANEDEV
07:48
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 162
    public function refresh()
47
    {
48 162
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
49 162
            ->get($this->instanceUrl(), $this->retrieveParameters);
50
51
52
        /** @var \Arcanedev\Stripe\Http\Response $response */
53 141
        $this->setLastResponse($response);
54 136
        $this->refreshFrom($response->getJson(), $this->opts);
55
56 136
        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 212
        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 224
        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 218
        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 132
        $opts = $this->opts->merge($options);
155
156
        /** @var \Arcanedev\Stripe\Http\Response $response */
157 132
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
158 132
        $this->setLastResponse($response);
159
160 132
        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 158
        $class    = get_called_class();
204
205
        /** @var self $resource */
206 158
        $resource = new $class($id, RequestOptions::parse($options));
207 158
        $resource->refresh();
208
209 132
        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 58
        $object = Util::convertToStripeObject($response->getJson(), $opts);
232
233 58
        self::checkIsCollectionObject($object);
234
235 58
        $object->setLastResponse($response);
236 58
        $object->setRequestParams($params);
237
238 58
        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 34
        self::checkArguments($params, $options);
279
280
        /** @var \Arcanedev\Stripe\Http\Response $response */
281 34
        list($response, $opts) = static::staticRequest('post', static::resourceUrl($id), $params, $options);
282
283 34
        $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 34
        $object->setLastResponse($response);
285
286 34
        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 74
        if (count($params = $this->serializeParameters()) > 0) {
301 66
            self::checkArguments(null, $options);
302 66
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
303 66
            $this->refreshFrom($response, $opts);
304 33
        }
305
306 74
        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 88
                '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 58
        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 58
    }
432
}
433