Completed
Pull Request — master (#52)
by ARCANEDEV
07:42
created

StripeResource::classUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
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 522
    public static function baseUrl()
37
    {
38 522
        return Stripe::getApiBaseUrl();
39 4
    }
40
41
    /**
42
     * Get the refreshed resource.
43
     *
44
     * @return self
45
     */
46 255
    public function refresh()
47
    {
48 255
        list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl())
49 255
            ->get($this->instanceUrl(), $this->retrieveParameters, $this->opts->headers);
50
51
        /** @var \Arcanedev\Stripe\Http\Response $response */
52 216
        $this->setLastResponse($response);
53 216
        $this->refreshFrom($response->getJson(), $this->opts);
54
55 216
        return $this;
56
    }
57
58
    /**
59
     * Get The name of the class, with namespacing and underscores stripped.
60
     *
61
     * @param  string  $class
62
     *
63
     * @return string
64
     */
65 495
    public static function className($class = '')
66
    {
67 495
        $name = self::getShortNameClass($class);
68 495
        $name = str_split_camelcase($name, '_');
69
70 495
        return strtolower(urlencode($name));
71
    }
72
73
    /**
74
     * Get Class short name.
75
     *
76
     * @param  string  $class
77
     *
78
     * @return string
79
     */
80 495
    protected static function getShortNameClass($class = '')
81
    {
82 495
        if (empty($class))
83 487
            $class = get_called_class();
84
85 495
        $class = new ReflectionClass($class);
86
87 495
        return $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 486
    public static function classUrl($class = '')
98
    {
99 486
        $base = self::className($class);
100
101 486
        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 330
        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 348
        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 339
        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 207
        $opts = $this->opts->merge($options);
154
155
        /** @var \Arcanedev\Stripe\Http\Response $response */
156 207
        list($response, $options) = static::staticRequest($method, $url, $params, $opts);
157 207
        $this->setLastResponse($response);
158
159 207
        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 492
        $opts      = RequestOptions::parse($options);
175 492
        $requestor = Requestor::make($opts->apiKey, static::baseUrl());
176
177 480
        list($response, $opts->apiKey) =
178 492
            $requestor->request($method, $url, $params, $opts->headers);
179
180 480
        foreach ($opts->headers as $k => $v) {
181 30
            if ( ! array_key_exists($k, self::$persistedHeaders))
182 21
                unset($opts->headers[$k]);
183 160
        }
184
185 480
        return [$response, $opts];
186
    }
187
188
    /* ------------------------------------------------------------------------------------------------
189
     |  CRUD Scope Functions
190
     | ------------------------------------------------------------------------------------------------
191
     */
192
    /**
193
     * Retrieve scope.
194
     *
195
     * @param  string             $id
196
     * @param  array|string|null  $options
197
     *
198
     * @return self
199
     */
200
    protected static function scopedRetrieve($id, $options = null)
201
    {
202 249
        $class    = get_called_class();
203
204
        /** @var self $resource */
205 249
        $resource = new $class($id, RequestOptions::parse($options));
206 249
        $resource->refresh();
207
208 210
        return $resource;
209
    }
210
211
    /**
212
     * List scope.
213
     *
214
     * @param  array|null         $params
215
     * @param  array|string|null  $options
216
     *
217
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
218
     *
219
     * @return \Arcanedev\Stripe\Collection|array
220
     */
221
    protected static function scopedAll($params = [], $options = null)
222
    {
223 90
        self::checkArguments($params, $options);
224
225 84
        $url = static::classUrl();
226
227
        /** @var \Arcanedev\Stripe\Http\Response $response */
228 84
        list($response, $opts) = self::staticRequest('get', $url, $params, $options);
229
230 84
        $object = Util::convertToStripeObject($response->getJson(), $opts);
231
232 84
        self::checkIsCollectionObject($object);
233
234 84
        $object->setLastResponse($response);
235 84
        $object->setRequestParams($params);
236
237 84
        return $object;
238
    }
239
240
    /**
241
     * Create scope.
242
     *
243
     * @param  array|null         $params
244
     * @param  array|string|null  $options
245
     *
246
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
247
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
248
     *
249
     * @return self
250
     */
251
    protected static function scopedCreate($params = [], $options = null)
252
    {
253 411
        self::checkArguments($params, $options);
254
255
        /** @var \Arcanedev\Stripe\Http\Response $response */
256 411
        list($response, $opts) = static::staticRequest('post', static::classUrl(), $params, $options);
257
258 399
        $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 261 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedCreate of type Arcanedev\Stripe\StripeResource.
Loading history...
259 399
        $object->setLastResponse($response);
260
261 399
        return $object;
262
    }
263
264
    /**
265
     * Update scope.
266
     *
267
     * @param  string             $id
268
     * @param  array|null         $params
269
     * @param  array|string|null  $options
270
     *
271
     * @return self
272
     *
273
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
274
     */
275
    protected static function scopedUpdate($id, $params = null, $options = null)
276
    {
277 48
        self::checkArguments($params, $options);
278
279
        /** @var \Arcanedev\Stripe\Http\Response $response */
280 48
        list($response, $opts) = static::staticRequest('post', static::resourceUrl($id), $params, $options);
281
282 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 285 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...
283 48
        $object->setLastResponse($response);
284
285 48
        return $object;
286
    }
287
288
    /**
289
     * Save scope.
290
     *
291
     * @param  array|string|null  $options
292
     *
293
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
294
     *
295
     * @return self
296
     */
297
    protected function scopedSave($options = null)
298
    {
299 117
        if (count($params = $this->serializeParameters()) > 0) {
300 102
            self::checkArguments(null, $options);
301 102
            list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options);
302 102
            $this->refreshFrom($response, $opts);
303 34
        }
304
305 117
        return $this;
306
    }
307
308
    /**
309
     * Delete Scope.
310
     *
311
     * @param  array|null         $params
312
     * @param  array|string|null  $options
313
     *
314
     * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException
315
     *
316
     * @return self
317
     */
318
    protected function scopedDelete($params = [], $options = null)
319
    {
320 42
        self::checkArguments($params, $options);
321
322 42
        list($response, $opts) = $this->request('delete', $this->instanceUrl(), $params, $options);
323 42
        $this->refreshFrom($response, $opts);
324
325 42
        return $this;
326
    }
327
328
    /* ------------------------------------------------------------------------------------------------
329
     |  Custom Scope Functions
330
     | ------------------------------------------------------------------------------------------------
331
     */
332
    /**
333
     * Custom Post Call.
334
     *
335
     * @param  string             $url
336
     * @param  array|null         $params
337
     * @param  array|string|null  $options
338
     *
339
     * @return self
340
     */
341
    protected function scopedPostCall($url, $params = [], $options = null)
342
    {
343
        /** @var \Arcanedev\Stripe\Http\Response $response */
344 27
        list($response, $options) = Requestor::make(RequestOptions::parse($options)->getApiKey(), static::baseUrl())
345 27
            ->post($url, $params);
346
347 27
        $this->refreshFrom($response->getJson(), $options);
348 27
        $this->setLastResponse($response);
349
350 27
        return $this;
351
    }
352
353
    /* ------------------------------------------------------------------------------------------------
354
     |  Check Functions
355
     | ------------------------------------------------------------------------------------------------
356
     */
357
    /**
358
     * Check Arguments.
359
     *
360
     * @param  array|null         $params
361
     * @param  array|string|null  $options
362
     *
363
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
364
     * @throws \Arcanedev\Stripe\Exceptions\BadMethodCallException
365
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
366
     */
367
    protected static function checkArguments($params = [], $options = null)
368
    {
369 489
        self::checkParameters($params);
370 486
        self::checkOptions($options);
371 483
    }
372
373
    /**
374
     * Check parameters.
375
     *
376
     * @param  array|null  $params
377
     *
378
     * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException
379
     */
380
    private static function checkParameters($params)
381
    {
382 489
        if ($params && ! is_array($params)) {
383 3
            throw new Exceptions\InvalidArgumentException(
384
                'You must pass an array as the first argument to Stripe API method calls.  '
385
                . '(HINT: an example call to create a charge would be: '
386 1
                . 'StripeCharge::create([\'amount\' => 100, \'currency\' => \'usd\', '
387 1
                . '\'card\' => [\'number\' => 4242424242424242, \'exp_month\' => 5, '
388 3
                . '\'exp_year\' => 2015]]))');
389
        }
390 486
    }
391
392
    /**
393
     * Check Options.
394
     *
395
     * @param  array|string|null  $options
396
     *
397
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
398
     */
399
    private static function checkOptions($options)
400
    {
401 486
        if ($options && (
402 45
                ! $options instanceof RequestOptions &&
403 41
                ! is_string($options) &&
404 184
                ! is_array($options)
405 11
            )
406 162
        ) {
407 3
            throw new Exceptions\ApiException(
408
                'The second argument to Stripe API method calls is an '
409 92
                . 'optional per-request apiKey, which must be a string.  '
410 3
                . '(HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")',
411 2
                500
412 1
            );
413
        }
414 483
    }
415
416
    /**
417
     * Check the object is a Collection class.
418
     *
419
     * @param  mixed  $object
420
     *
421
     * @throws \Arcanedev\Stripe\Exceptions\ApiException
422
     */
423
    private static function checkIsCollectionObject($object)
424
    {
425 84
        if ( ! is_a($object, Collection::class)) {
426
            throw new Exceptions\ApiException(
427
                'Expected type "Arcanedev\Stripe\Collection", got "'.get_class($object).'" instead'
428
            );
429
        }
430 84
    }
431
}
432