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