Completed
Push — master ( 725043...fc3a8f )
by Vladimir
07:42
created

ApiObject::checkInvalid()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
3
/**
4
 * This file contains the ApiObject class
5
 *
6
 * @copyright 2015 Vladimir Jimenez
7
 * @license   https://github.com/allejo/PhpPulse/blob/master/LICENSE.md MIT
8
 */
9
10
namespace allejo\DaPulse\Objects;
11
12
use allejo\DaPulse\Exceptions\InvalidObjectException;
13
use allejo\DaPulse\Utilities\UrlQuery;
14
15
/**
16
 * The base class for all DaPulse API objects
17
 *
18
 * @internal
19
 * @package allejo\DaPulse\Objects
20
 * @since   0.1.0
21
 */
22
abstract class ApiObject
23
{
24
    /**
25
     * The namespace used for all main PhpPulse objects. This is value is prepended before PhpPulse objects when being
26
     * checked with `instanceof`.
27
     *
28
     * @internal
29
     */
30
    const OBJ_NAMESPACE = "\\allejo\\DaPulse\\";
31
32
    /**
33
     * The default API protocol used for URL calls
34
     *
35
     * @internal
36
     */
37
    const API_PROTOCOL = "https";
38
39
    /**
40
     * The API end point for URL calls
41
     *
42
     * @internal
43
     */
44
    const API_ENDPOINT = "api.dapulse.com";
45
46
    /**
47
     * The API version used for URL calls
48
     *
49
     * @internal
50
     */
51
    const API_VERSION = "v1";
52
53
    /**
54
     * The suffix that is appended to the URL to access functionality for certain objects
55
     *
56
     * @internal
57
     */
58
    const API_PREFIX = "";
59
60
    /**
61
     * The API key used to make the URL calls
62
     *
63
     * @var string
64
     */
65
    protected static $apiKey;
66
67
    /**
68
     * When set to true, the object can only be constructed from an associative array of data. It will not attempt
69
     * to fetch the data with an API call; this is intended for objects are not directly accessible via the API.
70
     *
71
     * @var bool
72
     */
73
    protected $arrayConstructionOnly = false;
74
75
    /**
76
     * Set to true if the object has been deleted via an API call but the instance still exists. This variable will
77
     * prevent further API calls to a nonexistent object.
78
     *
79
     * @var bool
80
     */
81
    protected $deletedObject = false;
82
83
    /**
84
     * An associative array representing the original JSON response from DaPulse
85
     *
86
     * @var array
87
     */
88
    protected $jsonResponse;
89
90
    /**
91
     * Create an object from an API call
92
     *
93
     * @param int|array $idOrArray Either the numerical ID of an object or an associative array representing a JSON
94
     *                             response from an API call
95
     *
96
     * @throw \InvalidArgumentException The specified object cannot be created directly from an API call but instead
97
     *                                  requires an associative array of information gathered from other API calls.
98
     *
99
     * @since 0.1.0
100
     */
101
    public function __construct ($idOrArray)
102
    {
103
        $urlEndPoint = "";
104
        $staticClass = explode("\\", get_called_class());
105
        $staticClass = end($staticClass);
106
107
        if (is_null($idOrArray))
108
        {
109
            throw new \InvalidArgumentException("You may not initialize " . $staticClass . " with null.");
110
        }
111
112
        if (!is_array($idOrArray))
113
        {
114
            $urlEndPoint = sprintf("%s/%d.json", self::apiEndpoint(), $idOrArray);
115
        }
116
117
        if ($this->arrayConstructionOnly && !is_array($idOrArray))
118
        {
119
            throw new \InvalidArgumentException("A " . $staticClass . " cannot be fetched from an ID.");
120
        }
121
122
        $this->jsonResponse = (is_array($idOrArray)) ? $idOrArray : $this::sendGet($urlEndPoint);
0 ignored issues
show
Documentation Bug introduced by
It seems like is_array($idOrArray) ? $...::sendGet($urlEndPoint) of type * is incompatible with the declared type array of property $jsonResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
123
124
        $this->initializeValues();
125
        $this->assignResults();
126
    }
127
128
    // ================================================================================================================
129
    //   Getter functions
130
    // ================================================================================================================
131
132
    /**
133
     * Access the JSON response from DaPulse directly
134
     *
135
     * @since  0.1.0
136
     *
137
     * @return array
138
     */
139
    final public function getJson ()
140
    {
141
        return $this->jsonResponse;
142
    }
143
144
    // ================================================================================================================
145
    //   Helper functions
146
    // ================================================================================================================
147
148
    /**
149
     * Assign an associative array from a JSON response and map them to instance variables
150
     *
151
     * @since 0.1.0
152
     */
153
    final protected function assignResults ()
154
    {
155
        foreach ($this->jsonResponse as $key => $val)
156
        {
157
            if (property_exists(get_called_class(), $key))
158
            {
159
                $this->$key = $val;
160
            }
161
        }
162
    }
163
164
    /**
165
     * Check if the current object has been marked as deleted from DaPulse. If so, throw an exception.
166
     *
167
     * @throws InvalidObjectException
168
     */
169
    final protected function checkInvalid ()
170
    {
171
        if ($this->deletedObject)
172
        {
173
            throw new InvalidObjectException("This object no longer exists on DaPulse", 2);
174
        }
175
    }
176
177
    /**
178
     * Store the value in an array if the value is not null. This function is a shortcut of setting values in an array
179
     * only if they are not null, if not leave them unset; used ideally for PUT requests.
180
     *
181
     * @param array  $array The array that will store all of the POST parameters
182
     * @param string $name  The name of the field
183
     * @param mixed  $value The value to be stored in a given field
184
     */
185
    final protected static function setIfNotNullOrEmpty (&$array, $name, $value)
186
    {
187
        if (!is_null($value) || !empty($value))
188
        {
189
            $array[$name] = $value;
190
        }
191
    }
192
193
    // ================================================================================================================
194
    //   Empty functions
195
    // ================================================================================================================
196
197
    /**
198
     * Overload this function if any class variables need to be initialized to a default value
199
     */
200
    protected function initializeValues ()
201
    {
202
    }
203
204
    // ================================================================================================================
205
    //   Lazy loading functions
206
    // ================================================================================================================
207
208
    /**
209
     * Inject data into the array that will be mapped into individual instance variables. This function must be called
210
     * **before** lazyCastAll() is called and maps the associative array to objects.
211
     *
212
     * @param array $target An array of associative arrays with data to be converted into objects
213
     * @param array $array  An associative array containing data to be merged with the key being the name of the
214
     *                      instance variable.
215
     *
216
     * @since 0.1.0
217
     *
218
     * @throw \InvalidArgumentException If either parameters are not arrays
219
     */
220
    final protected static function lazyInject (&$target, $array)
221
    {
222
        if (!is_array($target) || !is_array($array))
223
        {
224
            throw new \InvalidArgumentException("Both the target and array must be arrays");
225
        }
226
227
        // If the first element is an array, let's assume $target hasn't been lazily casted into objects
228
        if (is_array($target[0]))
229
        {
230
            foreach ($target as &$element)
231
            {
232
                $element = array_merge($element, $array);
233
            }
234
        }
235
    }
236
237
    /**
238
     * Convert the specified array into an array of object types if needed
239
     *
240
     * @param  string $objectType The class name of the Objects the items should be
241
     * @param  array  $array      The array to check
242
     *
243
     * @since  0.2.0
244
     */
245
    final protected static function lazyCastAll (&$array, $objectType)
246
    {
247
        if (self::lazyCastNeededOnArray($objectType, $array))
248
        {
249
            $array = self::castArrayToObjectArray($objectType, $array);
250
        }
251
    }
252
253
    /**
254
     * Convert the specified item into the specified object if needed
255
     *
256
     * @param mixed  $target     The item to check
257
     * @param string $objectType The class name of the Objects the items should be
258
     *
259
     * @since 0.2.0
260
     */
261
    final protected static function lazyCast (&$target, $objectType)
262
    {
263
        if (self::lazyCastNeeded($target, $objectType))
264
        {
265
            $object = ($objectType[0] == "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
266
            $target = new $object($target);
267
        }
268
    }
269
270
    /**
271
     * Check whether it is required for an array of JSON data to be converted into an array of the specified objects
272
     *
273
     * @param  string $objectType The class name of the Objects the items should be
274
     * @param  array  $array      The array to check
275
     *
276
     * @since  0.2.0
277
     *
278
     * @return bool True if the array needs to converted into an array of objects
279
     */
280
    final protected static function lazyCastNeededOnArray ($objectType, $array)
281
    {
282
        $firstItem = $array[0];
283
284
        return self::lazyCastNeeded($firstItem, $objectType);
285
    }
286
287
    /**
288
     * Check if an individual item needs to be lazily converted into an object
289
     *
290
     * @param  mixed  $target     The item to check
291
     * @param  string $objectType The class name of the Objects the items should be
292
     *
293
     * @since  0.2.0
294
     *
295
     * @return bool
296
     */
297
    final protected static function lazyCastNeeded ($target, $objectType)
298
    {
299
        $objectDefinition = ($objectType[0] === "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
300
301
        return !($target instanceof $objectDefinition);
302
    }
303
304
    /**
305
     * Sends a GET request for a JSON array and casts the response into an array of objects
306
     *
307
     * @param  string $url       The API endpoint to call to get the JSON response from
308
     * @param  string $className The class name of the Object type to cast to
309
     * @param  array  $params    An associative array of URL parameters that will be passed to the specific call. For
310
     *                           example, limiting the number of results or the pagination of results. **Warning** The
311
     *                           API key does NOT need to be passed here
312
     *
313
     * @since  0.2.0
314
     *
315
     * @return array
316
     */
317
    final protected static function fetchAndCastToObjectArray ($url, $className, $params = array())
318
    {
319
        $objects = self::sendGet($url, $params);
320
321
        return self::castArrayToObjectArray($className, $objects);
322
    }
323
324
    /**
325
     * Convert an array of associative arrays into a specific object
326
     *
327
     * @param  string $className The class name of the Object type
328
     * @param  array  $objects   An associative array to be converted into an object
329
     *
330
     * @since  0.2.0
331
     *
332
     * @return array An array of the specified objects
333
     */
334
    final protected static function castArrayToObjectArray ($className, $objects)
335
    {
336
        $class = self::OBJ_NAMESPACE . $className;
337
        $array = array();
338
339
        foreach ($objects as $post)
340
        {
341
            $array[] = new $class($post);
342
        }
343
344
        return $array;
345
    }
346
347
    // ================================================================================================================
348
    //   URL jobs functions
349
    // ================================================================================================================
350
351
    /**
352
     * Send a GET request to fetch the data from the specified URL
353
     *
354
     * @param  string $url    The API endpoint to call
355
     * @param  array  $params An associative array of URL parameters that will be passed to the specific call. For
356
     *                        example, limiting the number of results or the pagination of results. **Warning** The API
357
     *                        key does NOT need to be passed here
358
     *
359
     * @since  0.1.0
360
     *
361
     * @return mixed          An associative array of the JSON response from DaPulse
362
     */
363
    final protected static function sendGet ($url, $params = array())
364
    {
365
        $params["api_key"] = self::$apiKey;
366
367
        $urlQuery = new UrlQuery($url, $params);
368
369
        return $urlQuery->sendGet();
370
    }
371
372
    /**
373
     * Send a POST request to a specified URL
374
     *
375
     * @param  string $url
376
     * @param  array  $postParams
377
     * @param  array  $getParams
378
     *
379
     * @since  0.1.0
380
     *
381
     * @return mixed
382
     */
383
    final protected static function sendPost ($url, $postParams, $getParams = array())
384
    {
385
        return self::sendRequest("POST", $url, $postParams, $getParams);
386
    }
387
388
    /**
389
     * Send a PUT request to a specified URL
390
     *
391
     * @param  string $url
392
     * @param  array  $postParams
393
     * @param  array  $getParams
394
     *
395
     * @since  0.1.0
396
     *
397
     * @return mixed
398
     */
399
    final protected static function sendPut ($url, $postParams, $getParams = array())
400
    {
401
        return self::sendRequest("PUT", $url, $postParams, $getParams);
402
    }
403
404
    /**
405
     * Send a DELETE request to a specified URL
406
     *
407
     * @param  string $url
408
     * @param  array  $getParams
409
     *
410
     * @since  0.1.0
411
     *
412
     * @return mixed
413
     */
414
    final protected static function sendDelete ($url, $getParams = array())
415
    {
416
        return self::sendRequest("DELETE", $url, NULL, $getParams);
0 ignored issues
show
Documentation introduced by
NULL is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
417
    }
418
419
    /**
420
     * Send the appropriate URL request
421
     *
422
     * @param  string $type
423
     * @param  string $url
424
     * @param  array  $postParams
425
     * @param  array  $getParams
426
     *
427
     * @since  0.1.0
428
     *
429
     * @return mixed
430
     */
431
    private static function sendRequest ($type, $url, $postParams, $getParams)
432
    {
433
        $getParams["api_key"] = self::$apiKey;
434
435
        $urlQuery = new UrlQuery($url, $getParams);
436
437
        switch ($type)
438
        {
439
            case "POST":
440
                return $urlQuery->sendPost($postParams);
441
442
            case "PUT":
443
                return $urlQuery->sendPut($postParams);
444
445
            case "DELETE":
446
                return $urlQuery->sendDelete();
447
448
            default:
449
                throw new \InvalidArgumentException();
450
        }
451
    }
452
453
    // ================================================================================================================
454
    //   API key functions
455
    // ================================================================================================================
456
457
    /**
458
     * Get the base URL to use in all of the API calls
459
     *
460
     * @param  string|null $apiPrefix If the API end point is different from the class's constant, this value will be
461
     *                                used as the suffix for the API endpoint
462
     *
463
     * @since  0.1.0
464
     *
465
     * @return string The base URL to call
466
     */
467
    final protected static function apiEndpoint ($apiPrefix = NULL)
468
    {
469
        $apiSection = isset($apiPrefix) ? $apiPrefix : static::API_PREFIX;
470
471
        return sprintf("%s://%s/%s/%s", self::API_PROTOCOL, self::API_ENDPOINT, self::API_VERSION, $apiSection);
472
    }
473
474
    /**
475
     * Set the API for all calls to the API
476
     *
477
     * @param string $apiKey The API key used to access the DaPulse API
478
     *
479
     * @since 0.1.0
480
     */
481
    final public static function setApiKey ($apiKey)
482
    {
483
        self::$apiKey = $apiKey;
484
    }
485
}