Completed
Push — master ( 444c22...d9c9d8 )
by Vladimir
02:53
created

ApiObject::jsonArrayToObjectArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 2
eloc 6
nc 2
nop 2
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
105
        if (!is_array($idOrArray))
106
        {
107
            $urlEndPoint = sprintf("%s/%d.json", self::apiEndpoint(), $idOrArray);
108
        }
109
110
        if ($this->arrayConstructionOnly && !is_array($idOrArray))
111
        {
112
            throw new \InvalidArgumentException("A " . get_called_class() . " cannot be fetched from an ID.");
113
        }
114
115
        $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...
116
117
        $this->initializeValues();
118
        $this->assignResults();
119
    }
120
121
    /**
122
     * Access the JSON response from DaPulse directly
123
     *
124
     * @since  0.1.0
125
     *
126
     * @return array
127
     */
128
    public function getJson ()
129
    {
130
        return $this->jsonResponse;
131
    }
132
133
    /**
134
     * Assign an associative array from a JSON response and map them to instance variables
135
     *
136
     * @since 0.1.0
137
     */
138
    protected function assignResults ()
139
    {
140
        foreach($this->jsonResponse as $key => $val)
141
        {
142
            if (property_exists(get_called_class(), $key))
143
            {
144
                $this->$key = $val;
145
            }
146
        }
147
    }
148
149
    /**
150
     * Check if the current object has been marked as deleted from DaPulse. If so, throw an exception.
151
     *
152
     * @throws InvalidObjectException
153
     */
154
    protected function checkInvalid ()
155
    {
156
        if ($this->deletedObject)
157
        {
158
            throw new InvalidObjectException("This object no longer exists on DaPulse", 2);
159
        }
160
    }
161
162
    /**
163
     * Overload this function if any class variables need to be initialized to a default value
164
     */
165
    protected function initializeValues() {}
166
167
    /**
168
     * Inject data into the array that will be mapped into individual instance variables. This function must be called
169
     * **before** lazyArray() is called and maps the associative array to objects.
170
     *
171
     * @param array $target An array of associative arrays with data to be converted into objects
172
     * @param array $array  An associative array containing data to be merged with the key being the name of the
173
     *                      instance variable.
174
     *
175
     * @since 0.1.0
176
     *
177
     * @throw \InvalidArgumentException If either parameters are not arrays
178
     */
179
    protected static function lazyInject (&$target, $array)
180
    {
181
        if (!is_array($target) || !is_array($array))
182
        {
183
            throw new \InvalidArgumentException("Both the target and array must be arrays");
184
        }
185
186
        // If the first element is an array, let's assume $target hasn't been lazily casted into objects
187
        if (is_array($target[0]))
188
        {
189
            foreach ($target as &$element)
190
            {
191
                $element = array_merge($element, $array);
192
            }
193
        }
194
    }
195
196
    /**
197
     * Convert the specified item into the specified object if needed
198
     *
199
     * @param mixed  $target     The item to check
200
     * @param string $objectType The class name of the Objects the items should be
201
     *
202
     * @since 0.1.0
203
     */
204
    protected static function lazyLoad (&$target, $objectType)
205
    {
206
        if (self::lazyLoadConversionNeeded($target, $objectType))
207
        {
208
            $target = new $objectType($target);
209
        }
210
    }
211
212
    /**
213
     * Check if an individual item needs to be lazily converted into an object
214
     *
215
     * @param  mixed  $target     The item to check
216
     * @param  string $objectType The class name of the Objects the items should be
217
     *
218
     * @since  0.1.0
219
     *
220
     * @return bool
221
     */
222
    protected static function lazyLoadConversionNeeded ($target, $objectType)
223
    {
224
        $objectDefinition = "\\allejo\\DaPulse\\" . $objectType;
225
226
        return !($target instanceof $objectDefinition);
227
    }
228
229
    /**
230
     * Convert the specified array into an array of object types if needed
231
     *
232
     * @param  string $objectType The class name of the Objects the items should be
233
     * @param  array  $array      The array to check
234
     *
235
     * @since  0.1.0
236
     */
237
    protected static function lazyArray (&$array, $objectType)
238
    {
239
        if (self::lazyArrayConversionNeeded($objectType, $array))
240
        {
241
            $array = self::jsonArrayToObjectArray($objectType, $array);
242
        }
243
    }
244
245
    /**
246
     * Check whether it is required for an array of JSON data to be converted into an array of the specified objects
247
     *
248
     * @param  string $objectType The class name of the Objects the items should be
249
     * @param  array  $array      The array to check
250
     *
251
     * @since  0.1.0
252
     *
253
     * @return bool True if the array needs to converted into an array of objects
254
     */
255
    protected static function lazyArrayConversionNeeded ($objectType, $array)
256
    {
257
        $firstItem = $array[0];
258
259
        return self::lazyLoadConversionNeeded($firstItem, $objectType);
260
    }
261
262
    /**
263
     * Fetches a JSON array and convert them into an array of objects
264
     *
265
     * @param  string $url       The API endpoint to call to get the JSON response from
266
     * @param  string $className The class name of the Object type to cast to
267
     * @param  array  $params    An associative array of URL parameters that will be passed to the specific call. For
268
     *                           example, limiting the number of results or the pagination of results. **Warning** The API
269
     *                           key does NOT need to be passed here
270
     *
271
     * @since  0.1.0
272
     *
273
     * @return array
274
     */
275
    protected static function fetchJsonArrayToObjectArray ($url, $className, $params = array())
276
    {
277
        $objects = self::sendGet($url, $params);
278
279
        return self::jsonArrayToObjectArray($className, $objects);
280
    }
281
282
    /**
283
     * Convert an array of associative arrays into a specific object
284
     *
285
     * @param  string $className The class name of the Object type
286
     * @param  array  $objects   An associative array to be converted into an object
287
     *
288
     * @since  0.1.0
289
     *
290
     * @return array An array of the specified objects
291
     */
292
    protected static function jsonArrayToObjectArray ($className, $objects)
293
    {
294
        $class = self::OBJ_NAMESPACE . $className;
295
        $array = array();
296
297
        foreach ($objects as $post)
298
        {
299
            $array[] = new $class($post);
300
        }
301
302
        return $array;
303
    }
304
305
    /**
306
     * Store the value in an array if the value is not null. This function is a shortcut of setting values in an array
307
     * only if they are not null, if not leave them unset; used ideally for PUT requests.
308
     *
309
     * @param array  $array The array that will store all of the POST parameters
310
     * @param string $name  The name of the field
311
     * @param string $value The value to be stored in a given field
312
     */
313
    protected static function setIfNotNullOrEmpty (&$array, $name, $value)
314
    {
315
        if (!is_null($value) || !empty($value))
316
        {
317
            $array[$name] = $value;
318
        }
319
    }
320
321
    /**
322
     * Send a GET request to fetch the data from the specified URL
323
     *
324
     * @param  string $url    The API endpoint to call
325
     * @param  array  $params An associative array of URL parameters that will be passed to the specific call. For
326
     *                        example, limiting the number of results or the pagination of results. **Warning** The API
327
     *                        key does NOT need to be passed here
328
     *
329
     * @since  0.1.0
330
     *
331
     * @return mixed          An associative array of the JSON response from DaPulse
332
     */
333
    protected static function sendGet ($url, $params = array())
334
    {
335
        $params["api_key"] = self::$apiKey;
336
337
        $urlQuery = new UrlQuery($url, $params);
338
339
        return $urlQuery->sendGet();
340
    }
341
342
    /**
343
     * Send a POST request to a specified URL
344
     *
345
     * @param  string $url
346
     * @param  array  $postParams
347
     * @param  array  $getParams
348
     *
349
     * @since  0.1.0
350
     *
351
     * @return mixed
352
     */
353
    protected static function sendPost ($url, $postParams, $getParams = array())
354
    {
355
        return self::sendRequest("POST", $url, $postParams, $getParams);
356
    }
357
358
    /**
359
     * Send a PUT request to a specified URL
360
     *
361
     * @param  string $url
362
     * @param  array  $postParams
363
     * @param  array  $getParams
364
     *
365
     * @since  0.1.0
366
     *
367
     * @return mixed
368
     */
369
    protected static function sendPut ($url, $postParams, $getParams = array())
370
    {
371
        return self::sendRequest("PUT", $url, $postParams, $getParams);
372
    }
373
374
    /**
375
     * Send a DELETE request to a specified URL
376
     *
377
     * @param  string $url
378
     * @param  array  $getParams
379
     *
380
     * @since  0.1.0
381
     *
382
     * @return mixed
383
     */
384
    protected static function sendDelete ($url, $getParams = array())
385
    {
386
        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...
387
    }
388
389
    /**
390
     * Get the base URL to use in all of the API calls
391
     *
392
     * @param  string|null $apiPrefix If the API end point is different from the class's constant, this value will be
393
     *                                used as the suffix for the API endpoint
394
     *
395
     * @since  0.1.0
396
     *
397
     * @return string The base URL to call
398
     */
399
    protected static function apiEndpoint ($apiPrefix = NULL)
400
    {
401
        $apiSection = isset($apiPrefix) ? $apiPrefix : static::API_PREFIX;
402
403
        return sprintf("%s://%s/%s/%s", self::API_PROTOCOL, self::API_ENDPOINT, self::API_VERSION, $apiSection);
404
    }
405
406
    /**
407
     * Send the appropriate URL request
408
     *
409
     * @param  string $type
410
     * @param  string $url
411
     * @param  array  $postParams
412
     * @param  array  $getParams
413
     *
414
     * @since  0.1.0
415
     *
416
     * @return mixed
417
     */
418
    private static function sendRequest ($type, $url, $postParams, $getParams)
419
    {
420
        $getParams["api_key"] = self::$apiKey;
421
422
        $urlQuery = new UrlQuery($url, $getParams);
423
424
        switch ($type)
425
        {
426
            case "POST":
427
                return $urlQuery->sendPost($postParams);
428
429
            case "PUT":
430
                return $urlQuery->sendPut($postParams);
431
432
            case "DELETE":
433
                return $urlQuery->sendDelete();
434
435
            default:
436
                throw new \InvalidArgumentException();
437
        }
438
    }
439
440
    /**
441
     * Set the API for all calls to the API
442
     *
443
     * @param string $apiKey The API key used to access the DaPulse API
444
     *
445
     * @since 0.1.0
446
     */
447
    public static function setApiKey ($apiKey)
448
    {
449
        self::$apiKey = $apiKey;
450
    }
451
}