PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.7.2
GiveWP – Donation Plugin and Fundraising Platform v2.7.2
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / vendor / stripe / stripe-php / lib / StripeObject.php
give / vendor / stripe / stripe-php / lib Last commit date
ApiOperations 6 years ago Checkout 6 years ago Error 6 years ago HttpClient 6 years ago Issuing 6 years ago Radar 6 years ago Reporting 6 years ago Sigma 6 years ago Terminal 6 years ago Util 6 years ago Account.php 6 years ago AccountLink.php 6 years ago AlipayAccount.php 6 years ago ApiRequestor.php 6 years ago ApiResource.php 6 years ago ApiResponse.php 6 years ago ApplePayDomain.php 6 years ago ApplicationFee.php 6 years ago ApplicationFeeRefund.php 6 years ago Balance.php 6 years ago BalanceTransaction.php 6 years ago BankAccount.php 6 years ago BitcoinReceiver.php 6 years ago BitcoinTransaction.php 6 years ago Capability.php 6 years ago Card.php 6 years ago Charge.php 6 years ago Collection.php 6 years ago CountrySpec.php 6 years ago Coupon.php 6 years ago CreditNote.php 6 years ago Customer.php 6 years ago CustomerBalanceTransaction.php 6 years ago Discount.php 6 years ago Dispute.php 6 years ago EphemeralKey.php 6 years ago Event.php 6 years ago ExchangeRate.php 6 years ago File.php 6 years ago FileLink.php 6 years ago FileUpload.php 6 years ago Invoice.php 6 years ago InvoiceItem.php 6 years ago InvoiceLineItem.php 6 years ago IssuerFraudRecord.php 6 years ago LoginLink.php 6 years ago OAuth.php 6 years ago Order.php 6 years ago OrderItem.php 6 years ago OrderReturn.php 6 years ago PaymentIntent.php 6 years ago PaymentMethod.php 6 years ago Payout.php 6 years ago Person.php 6 years ago Plan.php 6 years ago Product.php 6 years ago Recipient.php 6 years ago RecipientTransfer.php 6 years ago Refund.php 6 years ago RequestTelemetry.php 6 years ago Review.php 6 years ago SKU.php 6 years ago SetupIntent.php 6 years ago SingletonApiResource.php 6 years ago Source.php 6 years ago SourceTransaction.php 6 years ago Stripe.php 6 years ago StripeObject.php 6 years ago Subscription.php 6 years ago SubscriptionItem.php 6 years ago SubscriptionSchedule.php 6 years ago TaxId.php 6 years ago TaxRate.php 6 years ago ThreeDSecure.php 6 years ago Token.php 6 years ago Topup.php 6 years ago Transfer.php 6 years ago TransferReversal.php 6 years ago UsageRecord.php 6 years ago UsageRecordSummary.php 6 years ago Webhook.php 6 years ago WebhookEndpoint.php 6 years ago WebhookSignature.php 6 years ago
StripeObject.php
524 lines
1 <?php
2
3 namespace Stripe;
4
5 /**
6 * Class StripeObject
7 *
8 * @package Stripe
9 */
10 class StripeObject 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::convertToStripeObject($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 = "Stripe 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 Stripe's API, "
163 . "probably as a result of a save(). The attributes currently "
164 . "available on this object are: $attrs";
165 Stripe::getLogger()->error($message);
166 return $nullval;
167 } else {
168 $class = get_class($this);
169 Stripe::getLogger()->error("Stripe 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 return $obj;
230 }
231
232 /**
233 * Refreshes this object using the provided values.
234 *
235 * @param array $values
236 * @param null|string|array|Util\RequestOptions $opts
237 * @param boolean $partial Defaults to false.
238 */
239 public function refreshFrom($values, $opts, $partial = false)
240 {
241 $this->_opts = Util\RequestOptions::parse($opts);
242
243 $this->_originalValues = self::deepCopy($values);
244
245 if ($values instanceof StripeObject) {
246 $values = $values->__toArray(true);
247 }
248
249 // Wipe old state before setting new. This is useful for e.g. updating a
250 // customer, where there is no persistent card parameter. Mark those values
251 // which don't persist as transient
252 if ($partial) {
253 $removed = new Util\Set();
254 } else {
255 $removed = new Util\Set(array_diff(array_keys($this->_values), array_keys($values)));
256 }
257
258 foreach ($removed->toArray() as $k) {
259 unset($this->$k);
260 }
261
262 $this->updateAttributes($values, $opts, false);
263 foreach ($values as $k => $v) {
264 $this->_transientValues->discard($k);
265 $this->_unsavedValues->discard($k);
266 }
267 }
268
269 /**
270 * Mass assigns attributes on the model.
271 *
272 * @param array $values
273 * @param null|string|array|Util\RequestOptions $opts
274 * @param boolean $dirty Defaults to true.
275 */
276 public function updateAttributes($values, $opts = null, $dirty = true)
277 {
278 foreach ($values as $k => $v) {
279 // Special-case metadata to always be cast as a StripeObject
280 // This is necessary in case metadata is empty, as PHP arrays do
281 // not differentiate between lists and hashes, and we consider
282 // empty arrays to be lists.
283 if (($k === "metadata") && (is_array($v))) {
284 $this->_values[$k] = StripeObject::constructFrom($v, $opts);
285 } else {
286 $this->_values[$k] = Util\Util::convertToStripeObject($v, $opts);
287 }
288 if ($dirty) {
289 $this->dirtyValue($this->_values[$k]);
290 }
291 $this->_unsavedValues->add($k);
292 }
293 }
294
295 /**
296 * @return array A recursive mapping of attributes to values for this object,
297 * including the proper value for deleted attributes.
298 */
299 public function serializeParameters($force = false)
300 {
301 $updateParams = [];
302
303 foreach ($this->_values as $k => $v) {
304 // There are a few reasons that we may want to add in a parameter for
305 // update:
306 //
307 // 1. The `$force` option has been set.
308 // 2. We know that it was modified.
309 // 3. Its value is a StripeObject. A StripeObject may contain modified
310 // values within in that its parent StripeObject doesn't know about.
311 //
312 $original = array_key_exists($k, $this->_originalValues) ? $this->_originalValues[$k] : null;
313 $unsaved = $this->_unsavedValues->includes($k);
314 if ($force || $unsaved || $v instanceof StripeObject) {
315 $updateParams[$k] = $this->serializeParamsValue(
316 $this->_values[$k],
317 $original,
318 $unsaved,
319 $force,
320 $k
321 );
322 }
323 }
324
325 // a `null` that makes it out of `serializeParamsValue` signals an empty
326 // value that we shouldn't appear in the serialized form of the object
327 $updateParams = array_filter(
328 $updateParams,
329 function ($v) {
330 return $v !== null;
331 }
332 );
333
334 return $updateParams;
335 }
336
337
338 public function serializeParamsValue($value, $original, $unsaved, $force, $key = null)
339 {
340 // The logic here is that essentially any object embedded in another
341 // object that had a `type` is actually an API resource of a different
342 // type that's been included in the response. These other resources must
343 // be updated from their proper endpoints, and therefore they are not
344 // included when serializing even if they've been modified.
345 //
346 // There are _some_ known exceptions though.
347 //
348 // For example, if the value is unsaved (meaning the user has set it), and
349 // it looks like the API resource is persisted with an ID, then we include
350 // the object so that parameters are serialized with a reference to its
351 // ID.
352 //
353 // Another example is that on save API calls it's sometimes desirable to
354 // update a customer's default source by setting a new card (or other)
355 // object with `->source=` and then saving the customer. The
356 // `saveWithParent` flag to override the default behavior allows us to
357 // handle these exceptions.
358 //
359 // We throw an error if a property was set explicitly but we can't do
360 // anything with it because the integration is probably not working as the
361 // user intended it to.
362 if ($value === null) {
363 return "";
364 } elseif (($value instanceof APIResource) && (!$value->saveWithParent)) {
365 if (!$unsaved) {
366 return null;
367 } elseif (isset($value->id)) {
368 return $value;
369 } else {
370 throw new \InvalidArgumentException(
371 "Cannot save property `$key` containing an API resource of type " .
372 get_class($value) . ". It doesn't appear to be persisted and is " .
373 "not marked as `saveWithParent`."
374 );
375 }
376 } elseif (is_array($value)) {
377 if (Util\Util::isList($value)) {
378 // Sequential array, i.e. a list
379 $update = [];
380 foreach ($value as $v) {
381 array_push($update, $this->serializeParamsValue($v, null, true, $force));
382 }
383 // This prevents an array that's unchanged from being resent.
384 if ($update !== $this->serializeParamsValue($original, null, true, $force, $key)) {
385 return $update;
386 }
387 } else {
388 // Associative array, i.e. a map
389 return Util\Util::convertToStripeObject($value, $this->_opts)->serializeParameters();
390 }
391 } elseif ($value instanceof StripeObject) {
392 $update = $value->serializeParameters($force);
393 if ($original && $unsaved && $key && static::getAdditiveParams()->includes($key)) {
394 $update = array_merge(self::emptyValues($original), $update);
395 }
396 return $update;
397 } else {
398 return $value;
399 }
400 }
401
402 public function jsonSerialize()
403 {
404 return $this->__toArray(true);
405 }
406
407 public function __toJSON()
408 {
409 return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
410 }
411
412 public function __toString()
413 {
414 $class = get_class($this);
415 return $class . ' JSON: ' . $this->__toJSON();
416 }
417
418 public function __toArray($recursive = false)
419 {
420 if ($recursive) {
421 return Util\Util::convertStripeObjectToArray($this->_values);
422 } else {
423 return $this->_values;
424 }
425 }
426
427 /**
428 * Sets all keys within the StripeObject as unsaved so that they will be
429 * included with an update when `serializeParameters` is called. This
430 * method is also recursive, so any StripeObjects contained as values or
431 * which are values in a tenant array are also marked as dirty.
432 */
433 public function dirty()
434 {
435 $this->_unsavedValues = new Util\Set(array_keys($this->_values));
436 foreach ($this->_values as $k => $v) {
437 $this->dirtyValue($v);
438 }
439 }
440
441 protected function dirtyValue($value)
442 {
443 if (is_array($value)) {
444 foreach ($value as $v) {
445 $this->dirtyValue($v);
446 }
447 } elseif ($value instanceof StripeObject) {
448 $value->dirty();
449 }
450 }
451
452 /**
453 * Produces a deep copy of the given object including support for arrays
454 * and StripeObjects.
455 */
456 protected static function deepCopy($obj)
457 {
458 if (is_array($obj)) {
459 $copy = [];
460 foreach ($obj as $k => $v) {
461 $copy[$k] = self::deepCopy($v);
462 }
463 return $copy;
464 } elseif ($obj instanceof StripeObject) {
465 return $obj::constructFrom(
466 self::deepCopy($obj->_values),
467 clone $obj->_opts
468 );
469 } else {
470 return $obj;
471 }
472 }
473
474 /**
475 * Returns a hash of empty values for all the values that are in the given
476 * StripeObject.
477 */
478 public static function emptyValues($obj)
479 {
480 if (is_array($obj)) {
481 $values = $obj;
482 } elseif ($obj instanceof StripeObject) {
483 $values = $obj->_values;
484 } else {
485 throw new \InvalidArgumentException(
486 "empty_values got got unexpected object type: " . get_class($obj)
487 );
488 }
489 $update = array_fill_keys(array_keys($values), "");
490 return $update;
491 }
492
493 /**
494 * @return object The last response from the Stripe API
495 */
496 public function getLastResponse()
497 {
498 return $this->_lastResponse;
499 }
500
501 /**
502 * Sets the last response from the Stripe API
503 *
504 * @param ApiResponse $resp
505 * @return void
506 */
507 public function setLastResponse($resp)
508 {
509 $this->_lastResponse = $resp;
510 }
511
512 /**
513 * Indicates whether or not the resource has been deleted on the server.
514 * Note that some, but not all, resources can indicate whether they have
515 * been deleted.
516 *
517 * @return bool Whether the resource is deleted.
518 */
519 public function isDeleted()
520 {
521 return isset($this->_values['deleted']) ? $this->_values['deleted'] : false;
522 }
523 }
524