app/Plugin/StripePaymentGateway42/vendor/stripe/stripe-php/lib/StripeObject.php line 218

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