PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 4.16.3
GiveWP – Donation Plugin and Fundraising Platform v4.16.3
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 2 years ago BillingPortal 2 years ago Checkout 2 years ago Exception 4 years ago FinancialConnections 2 years ago HttpClient 2 years ago Identity 2 years ago Issuing 2 years ago Radar 2 years ago Reporting 4 years ago Service 2 years ago Sigma 4 years ago Terminal 2 years ago TestHelpers 2 years ago Util 2 years ago Account.php 2 years ago AccountLink.php 4 years ago AlipayAccount.php 4 years ago ApiRequestor.php 2 years ago ApiResource.php 2 years ago ApiResponse.php 4 years ago ApplePayDomain.php 4 years ago ApplicationFee.php 2 years ago ApplicationFeeRefund.php 4 years ago Balance.php 4 years ago BalanceTransaction.php 4 years ago BankAccount.php 4 years ago BaseStripeClient.php 2 years ago BaseStripeClientInterface.php 4 years ago BitcoinReceiver.php 2 years ago BitcoinTransaction.php 4 years ago Capability.php 4 years ago Card.php 2 years ago CashBalance.php 2 years ago Charge.php 2 years ago Collection.php 2 years ago CountrySpec.php 4 years ago Coupon.php 2 years ago CreditNote.php 2 years ago CreditNoteLineItem.php 4 years ago Customer.php 2 years ago CustomerBalanceTransaction.php 4 years ago Discount.php 2 years ago Dispute.php 4 years ago EphemeralKey.php 4 years ago ErrorObject.php 4 years ago Event.php 2 years ago ExchangeRate.php 4 years ago File.php 2 years ago FileLink.php 4 years ago FundingInstructions.php 2 years ago Invoice.php 2 years ago InvoiceItem.php 2 years ago InvoiceLineItem.php 2 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 2 years ago OrderItem.php 4 years ago OrderReturn.php 4 years ago PaymentIntent.php 2 years ago PaymentLink.php 2 years ago PaymentMethod.php 2 years ago Payout.php 4 years ago Person.php 2 years ago Plan.php 2 years ago Price.php 2 years ago Product.php 2 years ago PromotionCode.php 2 years ago Quote.php 2 years ago Recipient.php 2 years ago RecipientTransfer.php 4 years ago Refund.php 2 years ago RequestTelemetry.php 4 years ago Review.php 4 years ago SKU.php 2 years ago SearchResult.php 2 years ago SetupAttempt.php 4 years ago SetupIntent.php 2 years ago ShippingRate.php 2 years ago SingletonApiResource.php 2 years ago Source.php 4 years ago SourceTransaction.php 4 years ago Stripe.php 2 years ago StripeClient.php 2 years ago StripeClientInterface.php 4 years ago StripeObject.php 2 years ago StripeStreamingClientInterface.php 4 years ago Subscription.php 2 years ago SubscriptionItem.php 2 years ago SubscriptionSchedule.php 2 years ago TaxCode.php 2 years ago TaxId.php 2 years ago TaxRate.php 4 years ago ThreeDSecure.php 4 years ago Token.php 4 years ago Topup.php 4 years ago Transfer.php 2 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
588 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 #[\ReturnTypeWillChange]
198 public function offsetSet($k, $v)
199 {
200 $this->{$k} = $v;
201 }
202
203 #[\ReturnTypeWillChange]
204 public function offsetExists($k)
205 {
206 return \array_key_exists($k, $this->_values);
207 }
208
209 #[\ReturnTypeWillChange]
210 public function offsetUnset($k)
211 {
212 unset($this->{$k});
213 }
214
215 #[\ReturnTypeWillChange]
216 public function offsetGet($k)
217 {
218 return \array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
219 }
220
221 /**
222 * @return int
223 */
224 #[\ReturnTypeWillChange]
225 public function count()
226 {
227 return \count($this->_values);
228 }
229
230 public function keys()
231 {
232 return \array_keys($this->_values);
233 }
234
235 public function values()
236 {
237 return \array_values($this->_values);
238 }
239
240 /**
241 * This unfortunately needs to be public to be used in Util\Util.
242 *
243 * @param array $values
244 * @param null|array|string|Util\RequestOptions $opts
245 *
246 * @return static the object constructed from the given values
247 */
248 public static function constructFrom($values, $opts = null)
249 {
250 $obj = new static(isset($values['id']) ? $values['id'] : null);
251 $obj->refreshFrom($values, $opts);
252
253 return $obj;
254 }
255
256 /**
257 * Refreshes this object using the provided values.
258 *
259 * @param array $values
260 * @param null|array|string|Util\RequestOptions $opts
261 * @param bool $partial defaults to false
262 */
263 public function refreshFrom($values, $opts, $partial = false)
264 {
265 $this->_opts = Util\RequestOptions::parse($opts);
266
267 $this->_originalValues = self::deepCopy($values);
268
269 if ($values instanceof StripeObject) {
270 $values = $values->toArray();
271 }
272
273 // Wipe old state before setting new. This is useful for e.g. updating a
274 // customer, where there is no persistent card parameter. Mark those values
275 // which don't persist as transient
276 if ($partial) {
277 $removed = new Util\Set();
278 } else {
279 $removed = new Util\Set(\array_diff(\array_keys($this->_values), \array_keys($values)));
280 }
281
282 foreach ($removed->toArray() as $k) {
283 unset($this->{$k});
284 }
285
286 $this->updateAttributes($values, $opts, false);
287 foreach ($values as $k => $v) {
288 $this->_transientValues->discard($k);
289 $this->_unsavedValues->discard($k);
290 }
291 }
292
293 /**
294 * Mass assigns attributes on the model.
295 *
296 * @param array $values
297 * @param null|array|string|Util\RequestOptions $opts
298 * @param bool $dirty defaults to true
299 */
300 public function updateAttributes($values, $opts = null, $dirty = true)
301 {
302 foreach ($values as $k => $v) {
303 // Special-case metadata to always be cast as a StripeObject
304 // This is necessary in case metadata is empty, as PHP arrays do
305 // not differentiate between lists and hashes, and we consider
306 // empty arrays to be lists.
307 if (('metadata' === $k) && (\is_array($v))) {
308 $this->_values[$k] = StripeObject::constructFrom($v, $opts);
309 } else {
310 $this->_values[$k] = Util\Util::convertToStripeObject($v, $opts);
311 }
312 if ($dirty) {
313 $this->dirtyValue($this->_values[$k]);
314 }
315 $this->_unsavedValues->add($k);
316 }
317 }
318
319 /**
320 * @param bool $force defaults to false
321 *
322 * @return array a recursive mapping of attributes to values for this object,
323 * including the proper value for deleted attributes
324 */
325 public function serializeParameters($force = false)
326 {
327 $updateParams = [];
328
329 foreach ($this->_values as $k => $v) {
330 // There are a few reasons that we may want to add in a parameter for
331 // update:
332 //
333 // 1. The `$force` option has been set.
334 // 2. We know that it was modified.
335 // 3. Its value is a StripeObject. A StripeObject may contain modified
336 // values within in that its parent StripeObject doesn't know about.
337 //
338 $original = \array_key_exists($k, $this->_originalValues) ? $this->_originalValues[$k] : null;
339 $unsaved = $this->_unsavedValues->includes($k);
340 if ($force || $unsaved || $v instanceof StripeObject) {
341 $updateParams[$k] = $this->serializeParamsValue(
342 $this->_values[$k],
343 $original,
344 $unsaved,
345 $force,
346 $k
347 );
348 }
349 }
350
351 // a `null` that makes it out of `serializeParamsValue` signals an empty
352 // value that we shouldn't appear in the serialized form of the object
353 return \array_filter(
354 $updateParams,
355 function ($v) {
356 return null !== $v;
357 }
358 );
359 }
360
361 public function serializeParamsValue($value, $original, $unsaved, $force, $key = null)
362 {
363 // The logic here is that essentially any object embedded in another
364 // object that had a `type` is actually an API resource of a different
365 // type that's been included in the response. These other resources must
366 // be updated from their proper endpoints, and therefore they are not
367 // included when serializing even if they've been modified.
368 //
369 // There are _some_ known exceptions though.
370 //
371 // For example, if the value is unsaved (meaning the user has set it), and
372 // it looks like the API resource is persisted with an ID, then we include
373 // the object so that parameters are serialized with a reference to its
374 // ID.
375 //
376 // Another example is that on save API calls it's sometimes desirable to
377 // update a customer's default source by setting a new card (or other)
378 // object with `->source=` and then saving the customer. The
379 // `saveWithParent` flag to override the default behavior allows us to
380 // handle these exceptions.
381 //
382 // We throw an error if a property was set explicitly but we can't do
383 // anything with it because the integration is probably not working as the
384 // user intended it to.
385 if (null === $value) {
386 return '';
387 }
388 if (($value instanceof ApiResource) && (!$value->saveWithParent)) {
389 if (!$unsaved) {
390 return null;
391 }
392 if (isset($value->id)) {
393 return $value;
394 }
395
396 throw new Exception\InvalidArgumentException(
397 "Cannot save property `{$key}` containing an API resource of type " .
398 \get_class($value) . ". It doesn't appear to be persisted and is " .
399 'not marked as `saveWithParent`.'
400 );
401 }
402 if (\is_array($value)) {
403 if (Util\Util::isList($value)) {
404 // Sequential array, i.e. a list
405 $update = [];
406 foreach ($value as $v) {
407 $update[] = $this->serializeParamsValue($v, null, true, $force);
408 }
409 // This prevents an array that's unchanged from being resent.
410 if ($update !== $this->serializeParamsValue($original, null, true, $force, $key)) {
411 return $update;
412 }
413 } else {
414 // Associative array, i.e. a map
415 return Util\Util::convertToStripeObject($value, $this->_opts)->serializeParameters();
416 }
417 } elseif ($value instanceof StripeObject) {
418 $update = $value->serializeParameters($force);
419 if ($original && $unsaved && $key && static::getAdditiveParams()->includes($key)) {
420 $update = \array_merge(self::emptyValues($original), $update);
421 }
422
423 return $update;
424 } else {
425 return $value;
426 }
427 }
428
429 /**
430 * @return mixed
431 */
432 #[\ReturnTypeWillChange]
433 public function jsonSerialize()
434 {
435 return $this->toArray();
436 }
437
438 /**
439 * Returns an associative array with the key and values composing the
440 * Stripe object.
441 *
442 * @return array the associative array
443 */
444 public function toArray()
445 {
446 $maybeToArray = function ($value) {
447 if (null === $value) {
448 return null;
449 }
450
451 return \is_object($value) && \method_exists($value, 'toArray') ? $value->toArray() : $value;
452 };
453
454 return \array_reduce(\array_keys($this->_values), function ($acc, $k) use ($maybeToArray) {
455 if ('_' === \substr((string) $k, 0, 1)) {
456 return $acc;
457 }
458 $v = $this->_values[$k];
459 if (Util\Util::isList($v)) {
460 $acc[$k] = \array_map($maybeToArray, $v);
461 } else {
462 $acc[$k] = $maybeToArray($v);
463 }
464
465 return $acc;
466 }, []);
467 }
468
469 /**
470 * Returns a pretty JSON representation of the Stripe object.
471 *
472 * @return string the JSON representation of the Stripe object
473 */
474 public function toJSON()
475 {
476 return \json_encode($this->toArray(), \JSON_PRETTY_PRINT);
477 }
478
479 public function __toString()
480 {
481 $class = static::class;
482
483 return $class . ' JSON: ' . $this->toJSON();
484 }
485
486 /**
487 * Sets all keys within the StripeObject as unsaved so that they will be
488 * included with an update when `serializeParameters` is called. This
489 * method is also recursive, so any StripeObjects contained as values or
490 * which are values in a tenant array are also marked as dirty.
491 */
492 public function dirty()
493 {
494 $this->_unsavedValues = new Util\Set(\array_keys($this->_values));
495 foreach ($this->_values as $k => $v) {
496 $this->dirtyValue($v);
497 }
498 }
499
500 protected function dirtyValue($value)
501 {
502 if (\is_array($value)) {
503 foreach ($value as $v) {
504 $this->dirtyValue($v);
505 }
506 } elseif ($value instanceof StripeObject) {
507 $value->dirty();
508 }
509 }
510
511 /**
512 * Produces a deep copy of the given object including support for arrays
513 * and StripeObjects.
514 *
515 * @param mixed $obj
516 */
517 protected static function deepCopy($obj)
518 {
519 if (\is_array($obj)) {
520 $copy = [];
521 foreach ($obj as $k => $v) {
522 $copy[$k] = self::deepCopy($v);
523 }
524
525 return $copy;
526 }
527 if ($obj instanceof StripeObject) {
528 return $obj::constructFrom(
529 self::deepCopy($obj->_values),
530 clone $obj->_opts
531 );
532 }
533
534 return $obj;
535 }
536
537 /**
538 * Returns a hash of empty values for all the values that are in the given
539 * StripeObject.
540 *
541 * @param mixed $obj
542 */
543 public static function emptyValues($obj)
544 {
545 if (\is_array($obj)) {
546 $values = $obj;
547 } elseif ($obj instanceof StripeObject) {
548 $values = $obj->_values;
549 } else {
550 throw new Exception\InvalidArgumentException(
551 'empty_values got unexpected object type: ' . \get_class($obj)
552 );
553 }
554
555 return \array_fill_keys(\array_keys($values), '');
556 }
557
558 /**
559 * @return null|ApiResponse The last response from the Stripe API
560 */
561 public function getLastResponse()
562 {
563 return $this->_lastResponse;
564 }
565
566 /**
567 * Sets the last response from the Stripe API.
568 *
569 * @param ApiResponse $resp
570 */
571 public function setLastResponse($resp)
572 {
573 $this->_lastResponse = $resp;
574 }
575
576 /**
577 * Indicates whether or not the resource has been deleted on the server.
578 * Note that some, but not all, resources can indicate whether they have
579 * been deleted.
580 *
581 * @return bool whether the resource is deleted
582 */
583 public function isDeleted()
584 {
585 return isset($this->_values['deleted']) ? $this->_values['deleted'] : false;
586 }
587 }
588