Completed
Pull Request — master (#22)
by ARCANEDEV
07:43
created

StripeResource::scopedUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
cc 1
eloc 7
nc 1
nop 3
ccs 6
cts 6
cp 1
crap 1
rs 9.4285
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 685
    public static function baseUrl()
37
    {
38 685
        return Stripe::getApiBaseUrl();
39
    }
40
41
    /**
42
     * Get the refreshed resource.
43
     *
44
     * @return self
45
     */
46 320
    public function refresh()
47
    {
48 320
        $url    = $this->instanceUrl();
49
50 320
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
51 320
            ->get($url, $this->retrieveParameters);
52
53
54
        /** @var \Arcanedev\Stripe\Http\Response $response */
55 265
        $this->setLastResponse($response);
56 265
        $this->refreshFrom($response->getJson(), $this->opts);
57
58 265
        return $this;
59
    }
60
61
    /**
62
     * Get The name of the class, with namespacing and underscores stripped.
63
     *
64
     * @param  string  $class
65
     *
66
     * @return string
67
     */
68 675
    public static function className($class = '')
69
    {
70 675
        $name = self::getShortNameClass($class);
71 675
        $name = str_split_camelcase($name, '_');
72
73 675
        return strtolower(urlencode($name));
74
    }
75
76
    /**
77
     * Get Class short name.
78
     *
79
     * @param  string  $class
80
     *
81
     * @return string
82
     */
83 675
    protected static function getShortNameClass($class = '')
84
    {
85 675
        if (empty($class)) {
86 655
            $class = get_called_class();
87 524
        }
88
89 675
        $class = new ReflectionClass($class);
90
91 675
        return $class->getShortName();
92
    }
93
94
    /**
95
     * Get the endpoint URL for the given class.
96
     *
97
     * @param  string  $class
98
     *
99
     * @return string
100
     */
101 660
    public static function classUrl($class = '')
102
    {
103 660
        $base = self::className($class);
104
105 660
        return "/v1/${base}s";
106
    }
107
108
    /**
109
     * Get Instance URL.
110
     *
111
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
112
     *
113
     * @return string
114
     */
115
    public function instanceUrl()
116
    {
117 435
        return static::resourceUrl($this['id']);
118
    }
119
120
    /**
121
     * Get the instance endpoint URL for the given class.
122
     *
123
     * @param  string  $id
124
     *
125
     * @return string
126
     *
127
     * @throws Exceptions\InvalidRequestException
128
     */
129
    public static function resourceUrl($id)
130
    {
131 440
        if ($id === null) {
132 15
            $class = get_called_class();
133 15
            throw new Exceptions\InvalidRequestException(
134 15
                "Could not determine which URL to request: $class instance has invalid ID: $id", null
135 12
            );
136
        }
137
138 425
        $base     = static::classUrl();
139 425
        $endpoint = urlencode(str_utf8($id));
140
141 425
        return "$base/$endpoint";
142
    }
143
144
    /* ------------------------------------------------------------------------------------------------
145
     |  Request Functions
146
     | ------------------------------------------------------------------------------------------------
147
     */
148
    /**
149
     * Make a request.
150
     *
151
     * @param  string             $method
152
     * @param  string             $url
153
     * @param  array|null         $params
154
     * @param  array|string|null  $options
155
     *
156
     * @return array
157
     */
158
    protected function request($method, $url, $params = [], $options = null)
159
    {
160 295
        $opts = $this->opts->merge($options);
161
162
        /** @var \Arcanedev\Stripe\Http\Response $response */
163 295
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
164 295
        $this->setLastResponse($response);
165
166 295
        return [$response->getJson(), $options];
167
    }
168
169
    /**
170
     * Make a request (static).
171
     *
172
     * @param  string             $method
173
     * @param  string             $url
174
     * @param  array|null         $params
175
     * @param  array|string|null  $options
176
     *
177
     * @return array
178
     */
179
    protected static function staticRequest($method, $url, $params, $options)
180
    {
181 659
        $opts      = RequestOptions::parse($options);
182 659
        $requestor = Requestor::make($opts->apiKey, static::baseUrl());
183
184 644
        list($response, $opts->apiKey) =
185 659
            $requestor->request($method, $url, $params, $opts->headers);
186
187 644
        foreach ($opts->headers as $k => $v) {
188 5
            if ( ! array_key_exists($k, self::$persistedHeaders)) {
189 5
                unset($opts->headers[$k]);
190 4
            }
191 515
        }
192
193 644
        return [$response, $opts];
194
    }
195
196
    /* ------------------------------------------------------------------------------------------------
197
     |  CRUD Scope Functions
198
     | ------------------------------------------------------------------------------------------------
199
     */
200
    /**
201
     * Retrieve scope.
202
     *
203
     * @param  string             $id
204
     * @param  array|string|null  $options
205
     *
206
     * @return self
207
     */
208
    protected static function scopedRetrieve($id, $options = null)
209
    {
210 310
        $class    = get_called_class();
211
212
        /** @var self $resource */
213 310
        $resource = new $class($id, RequestOptions::parse($options));
214 310
        $resource->refresh();
215
216 255
        return $resource;
217
    }
218
219
    /**
220
     * List scope.
221
     *
222
     * @param  array|null        $params
223
     * @param  array|string|null $options
224
     *
225
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
226
     *
227
     * @return \Arcanedev\Stripe\Collection|array
228
     */
229
    protected static function scopedAll($params = [], $options = null)
230
    {
231 125
        self::checkArguments($params, $options);
232
233 115
        $url = static::classUrl();
234
235
        /** @var \Arcanedev\Stripe\Http\Response $response */
236 115
        list($response, $opts) = self::staticRequest('get', $url, $params, $options);
237
238 115
        $object = Util::convertToStripeObject($response->getJson(), $opts);
239
240 115
        self::checkIsCollectionObject($object);
241
242 115
        $object->setLastResponse($response);
243 115
        $object->setRequestParams($params);
244
245 115
        return $object;
246
    }
247
248
    /**
249
     * Create scope.
250
     *
251
     * @param  array|null         $params
252
     * @param  array|string|null  $options
253
     *
254
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
255
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
256
     *
257
     * @return self
258
     */
259
    protected static function scopedCreate($params = [], $options = null)
260
    {
261 579
        self::checkArguments($params, $options);
262
263 579
        $url = static::classUrl();
264
265
        /** @var \Arcanedev\Stripe\Http\Response $response */
266 579
        list($response, $opts) = self::staticRequest('post', $url, $params, $options);
267
268 564
        $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 271 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedCreate of type Arcanedev\Stripe\StripeResource.
Loading history...
269 564
        $object->setLastResponse($response);
270
271 564
        return $object;
272
    }
273
274
    /**
275
     * Update scope.
276
     *
277
     * @param  string             $id
278
     * @param  array|null         $params
279
     * @param  array|string|null  $options
280
     *
281
     * @return self
282
     *
283
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
284
     */
285
    protected static function scopedUpdate($id, $params = null, $options = null)
286
    {
287 10
        self::checkArguments($params, $options);
288
289 10
        $url = static::resourceUrl($id);
290
291
        /** @var \Arcanedev\Stripe\Http\Response $response */
292 10
        list($response, $opts) = static::staticRequest('post', $url, $params, $options);
293
294 10
        $object = Util::convertToStripeObject($response->getJson(), $opts);
0 ignored issues
show
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...
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 297 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedUpdate of type Arcanedev\Stripe\StripeResource.
Loading history...
295 10
        $object->setLastResponse($response);
296
297 10
        return $object;
298
    }
299
300
    /**
301
     * Save scope.
302
     *
303
     * @param  array|string|null  $options
304
     *
305
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
306
     *
307
     * @return self
308
     */
309
    protected function scopedSave($options = null)
310
    {
311 170
        $params = $this->serializeParameters();
312
313 170
        if (count($params) > 0) {
314 150
            self::checkArguments(null, $options);
315 150
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
316 150
            $this->refreshFrom($response, $opts);
317 120
        }
318
319 170
        return $this;
320
    }
321
322
    /**
323
     * Delete Scope.
324
     *
325
     * @param  array|null         $params
326
     * @param  array|string|null  $options
327
     *
328
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
329
     *
330
     * @return self
331
     */
332
    protected function scopedDelete($params = [], $options = null)
333
    {
334 55
        self::checkArguments($params, $options);
335
336 55
        $url = $this->instanceUrl();
337
338 55
        list($response, $opts) = $this->request('delete', $url, $params, $options);
339 55
        $this->refreshFrom($response, $opts);
340
341 55
        return $this;
342
    }
343
344
    /* ------------------------------------------------------------------------------------------------
345
     |  Custom Scope Functions
346
     | ------------------------------------------------------------------------------------------------
347
     */
348
    /**
349
     * Custom Post Call.
350
     *
351
     * @param  string             $url
352
     * @param  array|null         $params
353
     * @param  array|string|null  $options
354
     *
355
     * @return self
356
     */
357
    protected function scopedPostCall($url, $params = [], $options = null)
358
    {
359 45
        $opts      = RequestOptions::parse($options);
360 45
        $requestor = Requestor::make($opts->getApiKey(), static::baseUrl());
361
362
        /** @var \Arcanedev\Stripe\Http\Response $response */
363 45
        list($response, $options) = $requestor->post($url, $params);
364
365 45
        $this->refreshFrom($response->getJson(), $options);
366 45
        $this->setLastResponse($response);
367
368 45
        return $this;
369
    }
370
371
    /* ------------------------------------------------------------------------------------------------
372
     |  Check Functions
373
     | ------------------------------------------------------------------------------------------------
374
     */
375
    /**
376
     * Check Arguments.
377
     *
378
     * @param  array|null         $params
379
     * @param  array|string|null  $options
380
     *
381
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
382
     * @throws \Arcanedev\Stripe\Exceptions\BadMethodCallException
383
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
384
     */
385
    private static function checkArguments($params = [], $options = null)
386
    {
387 664
        self::checkParameters($params);
388 659
        self::checkOptions($options);
389 654
    }
390
391
    /**
392
     * Check parameters.
393
     *
394
     * @param  array|null  $params
395
     *
396
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
397
     */
398
    private static function checkParameters($params)
399
    {
400 664
        if ($params && ! is_array($params)) {
401
            $message = 'You must pass an array as the first argument to Stripe API method calls.  '
402
                . '(HINT: an example call to create a charge would be: '
403 4
                . 'StripeCharge::create([\'amount\' => 100, \'currency\' => \'usd\', '
404 4
                . '\'card\' => [\'number\' => 4242424242424242, \'exp_month\' => 5, '
405 5
                . '\'exp_year\' => 2015]]))';
406
407 5
            throw new Exceptions\InvalidArgumentException($message);
408
        }
409 659
    }
410
411
    /**
412
     * Check Options.
413
     *
414
     * @param  array|string|null  $options
415
     *
416
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
417
     */
418
    private static function checkOptions($options)
419
    {
420 659
        if ($options && (
421 35
                ! $options instanceof RequestOptions &&
422 35
                ! is_string($options) &&
423 140
                ! is_array($options)
424 8
            )
425 527
        ) {
426
            $message = 'The second argument to Stripe API method calls is an '
427
                . 'optional per-request apiKey, which must be a string.  '
428 5
                . '(HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")';
429
430 5
            throw new Exceptions\ApiException($message, 500);
431
        }
432 654
    }
433
434
    /**
435
     * Check the object is a Collection class.
436
     *
437
     * @param  mixed  $object
438
     *
439
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
440
     */
441
    private static function checkIsCollectionObject($object)
442
    {
443 115
        if ( ! is_a($object, 'Arcanedev\\Stripe\\Collection')) {
444
            $class   = get_class($object);
445
            $message = 'Expected type "Arcanedev\Stripe\Collection", got "' . $class . '" instead';
446
447
            throw new Exceptions\ApiException($message);
448
        }
449 115
    }
450
}
451