Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,579 @@
1
+<?php
2
+
3
+namespace Telnyx;
4
+
5
+/**
6
+ * Class TelnyxObject
7
+ *
8
+ * @package Telnyx
9
+ */
10
+class TelnyxObject implements \ArrayAccess, \Countable, \JsonSerializable
11
+{
12
+    protected $_opts;
13
+    protected $_originalValues;
14
+    protected $_values;
15
+    protected $_unsavedValues;
16
+    protected $_transientValues;
17
+    protected $_retrieveOptions;
18
+    protected $_lastResponse;
19
+
20
+    /**
21
+     * @return Util\Set Attributes that should not be sent to the API because
22
+     *    they're not updatable (e.g. ID).
23
+     */
24
+    public static function getPermanentAttributes()
25
+    {
26
+        static $permanentAttributes = null;
27
+        if ($permanentAttributes === null) {
28
+            $permanentAttributes = new Util\Set([
29
+                'id',
30
+            ]);
31
+        }
32
+        return $permanentAttributes;
33
+    }
34
+
35
+    /**
36
+     * Additive objects are subobjects in the API that don't have the same
37
+     * semantics as most subobjects, which are fully replaced when they're set.
38
+     * This is best illustrated by example. The `source` parameter sent when
39
+     * updating a subscription is *not* additive; if we set it:
40
+     *
41
+     *     source[object]=card&source[number]=123
42
+     *
43
+     * We expect the old `source` object to have been overwritten completely. If
44
+     * the previous source had an `address_state` key associated with it and we
45
+     * didn't send one this time, that value of `address_state` is gone.
46
+     *
47
+     * By contrast, additive objects are those that will have new data added to
48
+     * them while keeping any existing data in place. The only known case of its
49
+     * use is for `metadata`, but it could in theory be more general. As an
50
+     * example, say we have a `metadata` object that looks like this on the
51
+     * server side:
52
+     *
53
+     *     metadata = ["old" => "old_value"]
54
+     *
55
+     * If we update the object with `metadata[new]=new_value`, the server side
56
+     * object now has *both* fields:
57
+     *
58
+     *     metadata = ["old" => "old_value", "new" => "new_value"]
59
+     *
60
+     * This is okay in itself because usually users will want to treat it as
61
+     * additive:
62
+     *
63
+     *     $obj->metadata["new"] = "new_value";
64
+     *     $obj->save();
65
+     *
66
+     * However, in other cases, they may want to replace the entire existing
67
+     * contents:
68
+     *
69
+     *     $obj->metadata = ["new" => "new_value"];
70
+     *     $obj->save();
71
+     *
72
+     * This is where things get a little bit tricky because in order to clear
73
+     * any old keys that may have existed, we actually have to send an explicit
74
+     * empty string to the server. So the operation above would have to send
75
+     * this form to get the intended behavior:
76
+     *
77
+     *     metadata[old]=&metadata[new]=new_value
78
+     *
79
+     * This method allows us to track which parameters are considered additive,
80
+     * and lets us behave correctly where appropriate when serializing
81
+     * parameters to be sent.
82
+     *
83
+     * @return Util\Set Set of additive parameters
84
+     */
85
+    public static function getAdditiveParams()
86
+    {
87
+        static $additiveParams = null;
88
+        if ($additiveParams === null) {
89
+            // Set `metadata` as additive so that when it's set directly we remember
90
+            // to clear keys that may have been previously set by sending empty
91
+            // values for them.
92
+            //
93
+            // It's possible that not every object has `metadata`, but having this
94
+            // option set when there is no `metadata` field is not harmful.
95
+            $additiveParams = new Util\Set([
96
+                'metadata',
97
+            ]);
98
+        }
99
+        return $additiveParams;
100
+    }
101
+
102
+    public function __construct($id = null, $opts = null)
103
+    {
104
+        list($id, $this->_retrieveOptions) = Util\Util::normalizeId($id);
105
+        $this->_opts = Util\RequestOptions::parse($opts);
106
+        $this->_originalValues = [];
107
+        $this->_values = [];
108
+        $this->_unsavedValues = new Util\Set();
109
+        $this->_transientValues = new Util\Set();
110
+        if ($id !== null) {
111
+            $this->_values['id'] = $id;
112
+        }
113
+    }
114
+
115
+    // Standard accessor magic methods
116
+    public function __set($k, $v)
117
+    {
118
+        if (static::getPermanentAttributes()->includes($k)) {
119
+            throw new \InvalidArgumentException(
120
+                "Cannot set $k on this object. HINT: you can't set: " .
121
+                join(', ', static::getPermanentAttributes()->toArray())
122
+            );
123
+        }
124
+
125
+        if ($v === "") {
126
+            throw new \InvalidArgumentException(
127
+                'You cannot set \''.$k.'\'to an empty string. '
128
+                .'We interpret empty strings as NULL in requests. '
129
+                .'You may set obj->'.$k.' = NULL to delete the property'
130
+            );
131
+        }
132
+
133
+        $this->_values[$k] = Util\Util::convertToTelnyxObject($v, $this->_opts);
134
+        $this->dirtyValue($this->_values[$k]);
135
+        $this->_unsavedValues->add($k);
136
+    }
137
+
138
+    public function __isset($k)
139
+    {
140
+        return isset($this->_values[$k]);
141
+    }
142
+
143
+    public function __unset($k)
144
+    {
145
+        unset($this->_values[$k]);
146
+        $this->_transientValues->add($k);
147
+        $this->_unsavedValues->discard($k);
148
+    }
149
+
150
+    public function &__get($k)
151
+    {
152
+        // function should return a reference, using $nullval to return a reference to null
153
+        $nullval = null;
154
+        if (!empty($this->_values) && array_key_exists($k, $this->_values)) {
155
+            return $this->_values[$k];
156
+        } elseif (!empty($this->_transientValues) && $this->_transientValues->includes($k)) {
157
+            $class = get_class($this);
158
+            $attrs = join(', ', array_keys($this->_values));
159
+            $message = "Telnyx Notice: Undefined property of $class instance: $k. "
160
+                    . "HINT: The $k attribute was set in the past, however. "
161
+                    . "It was then wiped when refreshing the object "
162
+                    . "with the result returned by Telnyx's API, "
163
+                    . "probably as a result of a save(). The attributes currently "
164
+                    . "available on this object are: $attrs";
165
+            Telnyx::getLogger()->error($message);
166
+            return $nullval;
167
+        } else {
168
+            $class = get_class($this);
169
+            Telnyx::getLogger()->error("Telnyx Notice: Undefined property of $class instance: $k");
170
+            return $nullval;
171
+        }
172
+    }
173
+
174
+    // Magic method for var_dump output. Only works with PHP >= 5.6
175
+    public function __debugInfo()
176
+    {
177
+        return $this->_values;
178
+    }
179
+
180
+    // ArrayAccess methods
181
+    public function offsetSet($k, $v)
182
+    {
183
+        $this->$k = $v;
184
+    }
185
+
186
+    public function offsetExists($k)
187
+    {
188
+        return array_key_exists($k, $this->_values);
189
+    }
190
+
191
+    public function offsetUnset($k)
192
+    {
193
+        unset($this->$k);
194
+    }
195
+
196
+    public function offsetGet($k)
197
+    {
198
+        return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
199
+    }
200
+
201
+    // Countable method
202
+    public function count()
203
+    {
204
+        return count($this->_values);
205
+    }
206
+
207
+    public function keys()
208
+    {
209
+        return array_keys($this->_values);
210
+    }
211
+
212
+    public function values()
213
+    {
214
+        return array_values($this->_values);
215
+    }
216
+
217
+    /**
218
+     * This unfortunately needs to be public to be used in Util\Util
219
+     *
220
+     * @param array $values
221
+     * @param null|string|array|Util\RequestOptions $opts
222
+     *
223
+     * @return static The object constructed from the given values.
224
+     */
225
+    public static function constructFrom($values, $opts = null)
226
+    {
227
+        $obj = new static(isset($values['id']) ? $values['id'] : null);
228
+        $obj->refreshFrom($values, $opts);
229
+
230
+        // If 'id' is called something else like 'call_control_id'
231
+        $class = get_class($obj);
232
+        if (defined($class . '::OBJECT_ID')) {
233
+            $obj->reassignId(static::OBJECT_ID);
234
+        }
235
+
236
+        return $obj;
237
+    }
238
+
239
+    /**
240
+     * Refreshes this object using the provided values.
241
+     *
242
+     * @param array $values
243
+     * @param null|string|array|Util\RequestOptions $opts
244
+     * @param boolean $partial Defaults to false.
245
+     */
246
+    public function refreshFrom($values, $opts, $partial = false)
247
+    {
248
+        $this->_opts = Util\RequestOptions::parse($opts);
249
+
250
+        $this->_originalValues = self::deepCopy($values);
251
+
252
+        if ($values instanceof TelnyxObject) {
253
+            $values = $values->toArray(true);
254
+        }
255
+
256
+        // Wipe old state before setting new.  This is useful for e.g. updating a
257
+        // customer, where there is no persistent card parameter.  Mark those values
258
+        // which don't persist as transient
259
+        if ($partial) {
260
+            $removed = new Util\Set();
261
+        } else {
262
+            $removed = new Util\Set(array_diff(array_keys($this->_values), array_keys($values)));
263
+        }
264
+
265
+        foreach ($removed->toArray() as $k) {
266
+            unset($this->$k);
267
+        }
268
+
269
+        $this->updateAttributes($values, $opts, false);
270
+        foreach ($values as $k => $v) {
271
+            $this->_transientValues->discard($k);
272
+            $this->_unsavedValues->discard($k);
273
+        }
274
+    }
275
+
276
+    /**
277
+     * Mass assigns attributes on the model.
278
+     *
279
+     * @param array $values
280
+     * @param null|string|array|Util\RequestOptions $opts
281
+     * @param boolean $dirty Defaults to true.
282
+     */
283
+    public function updateAttributes($values, $opts = null, $dirty = true)
284
+    {
285
+        foreach ($values as $k => $v) {
286
+            // Special-case metadata to always be cast as a TelnyxObject
287
+            // This is necessary in case metadata is empty, as PHP arrays do
288
+            // not differentiate between lists and hashes, and we consider
289
+            // empty arrays to be lists.
290
+            if (($k === "metadata") && (is_array($v))) {
291
+                $this->_values[$k] = TelnyxObject::constructFrom($v, $opts);
292
+            } else {
293
+                $this->_values[$k] = Util\Util::convertToTelnyxObject($v, $opts);
294
+            }
295
+            if ($dirty) {
296
+                $this->dirtyValue($this->_values[$k]);
297
+            }
298
+            $this->_unsavedValues->add($k);
299
+        }
300
+    }
301
+
302
+    /**
303
+     * @return array A recursive mapping of attributes to values for this object,
304
+     *    including the proper value for deleted attributes.
305
+     */
306
+    public function serializeParameters($force = false)
307
+    {
308
+        $updateParams = [];
309
+
310
+        foreach ($this->_values as $k => $v) {
311
+            // There are a few reasons that we may want to add in a parameter for
312
+            // update:
313
+            //
314
+            //   1. The `$force` option has been set.
315
+            //   2. We know that it was modified.
316
+            //   3. Its value is a TelnyxObject. A TelnyxObject may contain modified
317
+            //      values within in that its parent TelnyxObject doesn't know about.
318
+            //
319
+            $original = array_key_exists($k, $this->_originalValues) ? $this->_originalValues[$k] : null;
320
+            $unsaved = $this->_unsavedValues->includes($k);
321
+            if ($force || $unsaved || $v instanceof TelnyxObject) {
322
+                $updateParams[$k] = $this->serializeParamsValue(
323
+                    $this->_values[$k],
324
+                    $original,
325
+                    $unsaved,
326
+                    $force,
327
+                    $k
328
+                );
329
+            }
330
+        }
331
+
332
+        // a `null` that makes it out of `serializeParamsValue` signals an empty
333
+        // value that we shouldn't appear in the serialized form of the object
334
+        $updateParams = array_filter(
335
+            $updateParams,
336
+            function ($v) {
337
+                return $v !== null;
338
+            }
339
+        );
340
+
341
+        return $updateParams;
342
+    }
343
+
344
+
345
+    public function serializeParamsValue($value, $original, $unsaved, $force, $key = null)
346
+    {
347
+        // The logic here is that essentially any object embedded in another
348
+        // object that had a `type` is actually an API resource of a different
349
+        // type that's been included in the response. These other resources must
350
+        // be updated from their proper endpoints, and therefore they are not
351
+        // included when serializing even if they've been modified.
352
+        //
353
+        // There are _some_ known exceptions though.
354
+        //
355
+        // For example, if the value is unsaved (meaning the user has set it), and
356
+        // it looks like the API resource is persisted with an ID, then we include
357
+        // the object so that parameters are serialized with a reference to its
358
+        // ID.
359
+        //
360
+        // Another example is that on save API calls it's sometimes desirable to
361
+        // update a customer's default source by setting a new card (or other)
362
+        // object with `->source=` and then saving the customer. The
363
+        // `saveWithParent` flag to override the default behavior allows us to
364
+        // handle these exceptions.
365
+        //
366
+        // We throw an error if a property was set explicitly but we can't do
367
+        // anything with it because the integration is probably not working as the
368
+        // user intended it to.
369
+        if ($value === null) {
370
+            return "";
371
+        } elseif (($value instanceof APIResource) && (!$value->saveWithParent)) {
372
+            if (!$unsaved) {
373
+                return null;
374
+            } elseif (isset($value->id)) {
375
+                return $value;
376
+            } else {
377
+                throw new \InvalidArgumentException(
378
+                    "Cannot save property `$key` containing an API resource of type " .
379
+                    get_class($value) . ". It doesn't appear to be persisted and is " .
380
+                    "not marked as `saveWithParent`."
381
+                );
382
+            }
383
+        } elseif (is_array($value)) {
384
+            if (Util\Util::isList($value)) {
385
+                // Sequential array, i.e. a list
386
+                $update = [];
387
+                foreach ($value as $v) {
388
+                    array_push($update, $this->serializeParamsValue($v, null, true, $force));
389
+                }
390
+                // This prevents an array that's unchanged from being resent.
391
+                if ($update !== $this->serializeParamsValue($original, null, true, $force, $key)) {
392
+                    return $update;
393
+                }
394
+            } else {
395
+                // Associative array, i.e. a map
396
+                return Util\Util::convertToTelnyxObject($value, $this->_opts)->serializeParameters();
397
+            }
398
+        } elseif ($value instanceof TelnyxObject) {
399
+            $update = $value->serializeParameters($force);
400
+            if ($original && $unsaved && $key && static::getAdditiveParams()->includes($key)) {
401
+                $update = array_merge(self::emptyValues($original), $update);
402
+            }
403
+            return $update;
404
+        } else {
405
+            return $value;
406
+        }
407
+    }
408
+
409
+    public function jsonSerialize()
410
+    {
411
+        return $this->toArray(true);
412
+    }
413
+
414
+    /**
415
+     * Returns an associative array with the key and values composing the
416
+     * Stripe object.
417
+     *
418
+     * @return array the associative array
419
+     */
420
+    public function toArray()
421
+    {
422
+        $maybeToArray = function ($value) {
423
+            if (null === $value) {
424
+                return null;
425
+            }
426
+
427
+            return \is_object($value) && \method_exists($value, 'toArray') ? $value->toArray() : $value;
428
+        };
429
+
430
+        return \array_reduce(\array_keys($this->_values), function ($acc, $k) use ($maybeToArray) {
431
+            if ('_' === \substr((string) $k, 0, 1)) {
432
+                return $acc;
433
+            }
434
+            $v = $this->_values[$k];
435
+            if (Util\Util::isList($v)) {
436
+                $acc[$k] = \array_map($maybeToArray, $v);
437
+            } else {
438
+                $acc[$k] = $maybeToArray($v);
439
+            }
440
+
441
+            return $acc;
442
+        }, []);
443
+    }
444
+
445
+    /**
446
+     * Returns a pretty JSON representation of the Stripe object.
447
+     *
448
+     * @return string the JSON representation of the Stripe object
449
+     */
450
+    public function toJSON()
451
+    {
452
+        return \json_encode($this->toArray(), \JSON_PRETTY_PRINT);
453
+    }
454
+
455
+    public function __toString()
456
+    {
457
+        $class = \get_class($this);
458
+
459
+        return $class . ' JSON: ' . $this->toJSON();
460
+    }
461
+
462
+    /*
463
+    public function __toArray($recursive = false)
464
+    {
465
+        if ($recursive) {
466
+            return Util\Util::convertTelnyxObjectToArray($this->_values);
467
+        } else {
468
+            return $this->_values;
469
+        }
470
+    }
471
+    */
472
+
473
+    /**
474
+     * Sets all keys within the TelnyxObject as unsaved so that they will be
475
+     * included with an update when `serializeParameters` is called. This
476
+     * method is also recursive, so any TelnyxObjects contained as values or
477
+     * which are values in a tenant array are also marked as dirty.
478
+     */
479
+    public function dirty()
480
+    {
481
+        $this->_unsavedValues = new Util\Set(array_keys($this->_values));
482
+        foreach ($this->_values as $k => $v) {
483
+            $this->dirtyValue($v);
484
+        }
485
+    }
486
+
487
+    protected function dirtyValue($value)
488
+    {
489
+        if (is_array($value)) {
490
+            foreach ($value as $v) {
491
+                $this->dirtyValue($v);
492
+            }
493
+        } elseif ($value instanceof TelnyxObject) {
494
+            $value->dirty();
495
+        }
496
+    }
497
+
498
+    /**
499
+     * Produces a deep copy of the given object including support for arrays
500
+     * and TelnyxObjects.
501
+     */
502
+    protected static function deepCopy($obj)
503
+    {
504
+        if (is_array($obj)) {
505
+            $copy = [];
506
+            foreach ($obj as $k => $v) {
507
+                $copy[$k] = self::deepCopy($v);
508
+            }
509
+            return $copy;
510
+        } elseif ($obj instanceof TelnyxObject) {
511
+            return $obj::constructFrom(
512
+                self::deepCopy($obj->_values),
513
+                clone $obj->_opts
514
+            );
515
+        } else {
516
+            return $obj;
517
+        }
518
+    }
519
+
520
+    /**
521
+     * Returns a hash of empty values for all the values that are in the given
522
+     * TelnyxObject.
523
+     */
524
+    public static function emptyValues($obj)
525
+    {
526
+        if (is_array($obj)) {
527
+            $values = $obj;
528
+        } elseif ($obj instanceof TelnyxObject) {
529
+            $values = $obj->_values;
530
+        } else {
531
+            throw new \InvalidArgumentException(
532
+                "empty_values got got unexpected object type: " . get_class($obj)
533
+            );
534
+        }
535
+        $update = array_fill_keys(array_keys($values), "");
536
+        return $update;
537
+    }
538
+
539
+    /**
540
+     * @return object The last response from the Telnyx API
541
+     */
542
+    public function getLastResponse()
543
+    {
544
+        return $this->_lastResponse;
545
+    }
546
+
547
+    /**
548
+     * Sets the last response from the Telnyx API
549
+     *
550
+     * @param ApiResponse $resp
551
+     * @return void
552
+     */
553
+    public function setLastResponse($resp)
554
+    {
555
+        $this->_lastResponse = $resp;
556
+    }
557
+
558
+    /**
559
+     * Indicates whether or not the resource has been deleted on the server.
560
+     * Note that some, but not all, resources can indicate whether they have
561
+     * been deleted.
562
+     *
563
+     * @return bool Whether the resource is deleted.
564
+     */
565
+    public function isDeleted()
566
+    {
567
+        return isset($this->_values['deleted']) ? $this->_values['deleted'] : false;
568
+    }
569
+
570
+    /**
571
+     * Reassigns another parameter as the id. Used for endpoints that return id in a different param such as /v2/calls
572
+     * @return void
573
+     */
574
+    public function reassignId($new_id) {
575
+        if (isset($this->_values[$new_id])) {
576
+            $this->_values['id'] = $this->_values[$new_id];
577
+        }
578
+    }
579
+}