Completed
Push — develop ( 205ec8...3516bb )
by Vladimir
03:24
created

ApiObject::sendPut()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 3
crap 1
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 implements \JsonSerializable
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 53
    public function __construct ($idOrArray)
102
    {
103 53
        $urlEndPoint = "";
104 53
        $staticClass = explode("\\", get_called_class());
105 53
        $staticClass = end($staticClass);
106
107 53
        if (is_null($idOrArray))
108 53
        {
109
            throw new \InvalidArgumentException("You may not initialize " . $staticClass . " with null.");
110
        }
111
112 53
        if (!is_array($idOrArray))
113 53
        {
114 53
            $urlEndPoint = sprintf("%s/%d.json", self::apiEndpoint(), $idOrArray);
115 53
        }
116
117 53
        if ($this->arrayConstructionOnly && !is_array($idOrArray))
118 53
        {
119
            throw new \InvalidArgumentException("A " . $staticClass . " cannot be fetched from an ID.");
120
        }
121
122 53
        $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 53
        $this->initializeValues();
125 53
        $this->assignResults();
126 53
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function jsonSerialize()
132
    {
133
        return $this->jsonResponse;
134
    }
135
136
    // ================================================================================================================
137
    //   Getter functions
138
    // ================================================================================================================
139
140
    /**
141
     * Access the JSON response from DaPulse directly
142
     *
143
     * @api
144
     * @deprecated 0.3.0 Feed this object to json_encode() to get the JSON representation of this object instead or call
145
     *                   `jsonSerialize()`
146
     * @since  0.1.0
147
     * @todo   Remove at 0.4.0 or next breaking release
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
148
     * @return array
149
     */
150
    final public function getJson ()
151
    {
152
        return $this->jsonSerialize();
153
    }
154
155
    // ================================================================================================================
156
    //   Helper functions
157
    // ================================================================================================================
158
159
    /**
160
     * Assign an associative array from a JSON response and map them to instance variables
161
     *
162
     * @since 0.1.0
163
     */
164 53
    final protected function assignResults ()
165
    {
166 53
        foreach ($this->jsonResponse as $key => $val)
167
        {
168 53
            if (property_exists(get_called_class(), $key))
169 53
            {
170 53
                $this->$key = $val;
171 53
            }
172 53
        }
173 53
    }
174
175
    /**
176
     * Check if the current object has been marked as deleted from DaPulse. If so, throw an exception.
177
     *
178
     * @throws InvalidObjectException
179
     */
180
    final protected function checkInvalid ()
181
    {
182
        if ($this->deletedObject)
183
        {
184
            throw new InvalidObjectException("This object no longer exists on DaPulse", 2);
185
        }
186
    }
187
188
    /**
189
     * Store the value in an array if the value is not null. This function is a shortcut of setting values in an array
190
     * only if they are not null, if not leave them unset; used ideally for PUT requests.
191
     *
192
     * @param array  $array The array that will store all of the POST parameters
193
     * @param string $name  The name of the field
194
     * @param mixed  $value The value to be stored in a given field
195
     */
196
    final protected static function setIfNotNullOrEmpty (&$array, $name, $value)
197
    {
198
        if (!is_null($value) || !empty($value))
199
        {
200
            $array[$name] = $value;
201
        }
202
    }
203
204
    // ================================================================================================================
205
    //   Empty functions
206
    // ================================================================================================================
207
208
    /**
209
     * Overload this function if any class variables need to be initialized to a default value
210
     */
211 46
    protected function initializeValues ()
212
    {
213 46
    }
214
215
    // ================================================================================================================
216
    //   Lazy loading functions
217
    // ================================================================================================================
218
219
    /**
220
     * Inject data into the array that will be mapped into individual instance variables. This function must be called
221
     * **before** lazyCastAll() is called and maps the associative array to objects.
222
     *
223
     * @param array $target An array of associative arrays with data to be converted into objects
224
     * @param array $array  An associative array containing data to be merged with the key being the name of the
225
     *                      instance variable.
226
     *
227
     * @since 0.1.0
228
     *
229
     * @throw \InvalidArgumentException If either parameters are not arrays
230
     */
231 15
    final protected static function lazyInject (&$target, $array)
232
    {
233 15
        if (!is_array($target) || !is_array($array))
234 15
        {
235
            throw new \InvalidArgumentException("Both the target and array must be arrays");
236
        }
237
238
        // If the first element is an array, let's assume $target hasn't been lazily casted into objects
239 15
        if (is_array($target[0]))
240 15
        {
241 15
            foreach ($target as &$element)
242
            {
243 15
                $element = array_merge($element, $array);
244 15
            }
245 15
        }
246 15
    }
247
248
    /**
249
     * Convert the specified array into an array of object types if needed
250
     *
251
     * @param  string $objectType The class name of the Objects the items should be
252
     * @param  array  $array      The array to check
253
     *
254
     * @since  0.2.0
255
     */
256 18
    final protected static function lazyCastAll (&$array, $objectType)
257
    {
258 18
        if (self::lazyCastNeededOnArray($objectType, $array))
259 18
        {
260 17
            $array = self::castArrayToObjectArray($objectType, $array);
261 17
        }
262 18
    }
263
264
    /**
265
     * Convert the specified item into the specified object if needed
266
     *
267
     * @param mixed  $target     The item to check
268
     * @param string $objectType The class name of the Objects the items should be
269
     *
270
     * @since 0.2.0
271
     */
272 4
    final protected static function lazyCast (&$target, $objectType)
273
    {
274 4
        if (self::lazyCastNeeded($target, $objectType))
275 4
        {
276 4
            $object = ($objectType[0] == "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
277 4
            $target = new $object($target);
278 4
        }
279 4
    }
280
281
    /**
282
     * Check whether it is required for an array of JSON data to be converted into an array of the specified objects
283
     *
284
     * @param  string $objectType The class name of the Objects the items should be
285
     * @param  array  $array      The array to check
286
     *
287
     * @since  0.2.0
288
     *
289
     * @return bool True if the array needs to converted into an array of objects
290
     */
291 18
    final protected static function lazyCastNeededOnArray ($objectType, $array)
292
    {
293 18
        if (is_array($array) && count($array) == 0) { return false; }
294
295 17
        $firstItem = $array[0];
296
297 17
        return self::lazyCastNeeded($firstItem, $objectType);
298
    }
299
300
    /**
301
     * Check if an individual item needs to be lazily converted into an object
302
     *
303
     * @param  mixed  $target     The item to check
304
     * @param  string $objectType The class name of the Objects the items should be
305
     *
306
     * @since  0.2.0
307
     *
308
     * @return bool
309
     */
310 21
    final protected static function lazyCastNeeded ($target, $objectType)
311
    {
312 21
        $objectDefinition = ($objectType[0] === "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
313
314 21
        return !($target instanceof $objectDefinition);
315
    }
316
317
    /**
318
     * Sends a GET request for a JSON array and casts the response into an array of objects
319
     *
320
     * @param  string $url       The API endpoint to call to get the JSON response from
321
     * @param  string $className The class name of the Object type to cast to
322
     * @param  array  $params    An associative array of URL parameters that will be passed to the specific call. For
323
     *                           example, limiting the number of results or the pagination of results. **Warning** The
324
     *                           API key does NOT need to be passed here
325
     *
326
     * @since  0.2.0
327
     *
328
     * @return array
329
     */
330 20
    final protected static function fetchAndCastToObjectArray ($url, $className, $params = array())
331
    {
332 20
        $objects = self::sendGet($url, $params);
333
334 20
        return self::castArrayToObjectArray($className, $objects);
335
    }
336
337
    /**
338
     * Convert an array of associative arrays into a specific object
339
     *
340
     * @param  string $className The class name of the Object type
341
     * @param  array  $objects   An associative array to be converted into an object
342
     *
343
     * @since  0.2.0
344
     *
345
     * @return array An array of the specified objects
346
     */
347 35
    final protected static function castArrayToObjectArray ($className, $objects)
348
    {
349 35
        $class = self::OBJ_NAMESPACE . $className;
350 35
        $array = array();
351
352 35
        foreach ($objects as $post)
353
        {
354 35
            $array[] = new $class($post);
355 35
        }
356
357 35
        return $array;
358
    }
359
360
    // ================================================================================================================
361
    //   URL jobs functions
362
    // ================================================================================================================
363
364
    /**
365
     * Send a GET request to fetch the data from the specified URL
366
     *
367
     * @param  string $url    The API endpoint to call
368
     * @param  array  $params An associative array of URL parameters that will be passed to the specific call. For
369
     *                        example, limiting the number of results or the pagination of results. **Warning** The API
370
     *                        key does NOT need to be passed here
371
     *
372
     * @since  0.1.0
373
     *
374
     * @return mixed          An associative array of the JSON response from DaPulse
375
     */
376 53
    final protected static function sendGet ($url, $params = array())
377
    {
378 53
        $params["api_key"] = self::$apiKey;
379
380 53
        $urlQuery = new UrlQuery($url, $params);
381
382 53
        return $urlQuery->sendGet();
383
    }
384
385
    /**
386
     * Send a POST request to a specified URL
387
     *
388
     * @param  string $url
389
     * @param  array  $postParams
390
     * @param  array  $getParams
391
     *
392
     * @since  0.1.0
393
     *
394
     * @return mixed
395
     */
396 3
    final protected static function sendPost ($url, $postParams, $getParams = array())
397
    {
398 3
        return self::sendRequest("POST", $url, $postParams, $getParams);
399
    }
400
401
    /**
402
     * Send a PUT request to a specified URL
403
     *
404
     * @param  string $url
405
     * @param  array  $postParams
406
     * @param  array  $getParams
407
     *
408
     * @since  0.1.0
409
     *
410
     * @return mixed
411
     */
412 7
    final protected static function sendPut ($url, $postParams, $getParams = array())
413
    {
414 7
        return self::sendRequest("PUT", $url, $postParams, $getParams);
415
    }
416
417
    /**
418
     * Send a DELETE request to a specified URL
419
     *
420
     * @param  string $url
421
     * @param  array  $getParams
422
     *
423
     * @since  0.1.0
424
     *
425
     * @return mixed
426
     */
427
    final protected static function sendDelete ($url, $getParams = array())
428
    {
429
        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...
430
    }
431
432
    /**
433
     * Send the appropriate URL request
434
     *
435
     * @param  string $type
436
     * @param  string $url
437
     * @param  array  $postParams
438
     * @param  array  $getParams
439
     *
440
     * @since  0.1.0
441
     *
442
     * @return mixed
443
     */
444 10
    private static function sendRequest ($type, $url, $postParams, $getParams)
445
    {
446 10
        $getParams["api_key"] = self::$apiKey;
447
448 10
        $urlQuery = new UrlQuery($url, $getParams);
449
450
        switch ($type)
451
        {
452 10
            case "POST":
453 3
                return $urlQuery->sendPost($postParams);
454
455 7
            case "PUT":
456 7
                return $urlQuery->sendPut($postParams);
457
458
            case "DELETE":
459
                return $urlQuery->sendDelete();
460
461
            default:
462
                throw new \InvalidArgumentException();
463
        }
464
    }
465
466
    // ================================================================================================================
467
    //   API key functions
468
    // ================================================================================================================
469
470
    /**
471
     * Get the base URL to use in all of the API calls
472
     *
473
     * @param  string|null $apiPrefix If the API end point is different from the class's constant, this value will be
474
     *                                used as the suffix for the API endpoint
475
     *
476
     * @since  0.1.0
477
     *
478
     * @return string The base URL to call
479
     */
480 53
    final protected static function apiEndpoint ($apiPrefix = NULL)
481
    {
482 53
        $apiSection = isset($apiPrefix) ? $apiPrefix : static::API_PREFIX;
483
484 53
        return sprintf("%s://%s/%s/%s", self::API_PROTOCOL, self::API_ENDPOINT, self::API_VERSION, $apiSection);
485
    }
486
487
    /**
488
     * Set the API for all calls to the API
489
     *
490
     * @param string $apiKey The API key used to access the DaPulse API
491
     *
492
     * @since 0.1.0
493
     */
494 53
    final public static function setApiKey ($apiKey)
495
    {
496 53
        self::$apiKey = $apiKey;
497 53
    }
498
}
499