/lib/Stripe/Object.php

https://gitlab.com/brownmestizo/design-sandbox · PHP · 255 lines · 219 code · 20 blank · 16 comment · 24 complexity · bbd64f0d3a79d77e83f2df037bab13fb MD5 · raw file

  1. <?php
  2. class Stripe_Object implements ArrayAccess
  3. {
  4. /**
  5. * @var array Attributes that should not be sent to the API because they're
  6. * not updatable (e.g. API key, ID).
  7. */
  8. public static $permanentAttributes;
  9. /**
  10. * @var array Attributes that are nested but still updatable from the parent
  11. * class's URL (e.g. metadata).
  12. */
  13. public static $nestedUpdatableAttributes;
  14. public static function init()
  15. {
  16. self::$permanentAttributes = new Stripe_Util_Set(array('_apiKey', 'id'));
  17. self::$nestedUpdatableAttributes = new Stripe_Util_Set(array('metadata'));
  18. }
  19. protected $_apiKey;
  20. protected $_values;
  21. protected $_unsavedValues;
  22. protected $_transientValues;
  23. protected $_retrieveOptions;
  24. public function __construct($id=null, $apiKey=null)
  25. {
  26. $this->_apiKey = $apiKey;
  27. $this->_values = array();
  28. $this->_unsavedValues = new Stripe_Util_Set();
  29. $this->_transientValues = new Stripe_Util_Set();
  30. $this->_retrieveOptions = array();
  31. if (is_array($id)) {
  32. foreach ($id as $key => $value) {
  33. if ($key != 'id')
  34. $this->_retrieveOptions[$key] = $value;
  35. }
  36. $id = $id['id'];
  37. }
  38. if ($id)
  39. $this->id = $id;
  40. }
  41. // Standard accessor magic methods
  42. public function __set($k, $v)
  43. {
  44. if ($v === "") {
  45. throw new InvalidArgumentException(
  46. 'You cannot set \''.$k.'\'to an empty string. '
  47. .'We interpret empty strings as NULL in requests. '
  48. .'You may set obj->'.$k.' = NULL to delete the property'
  49. );
  50. }
  51. if (self::$nestedUpdatableAttributes->includes($k) && isset($this->$k) && is_array($v)) {
  52. $this->$k->replaceWith($v);
  53. } else {
  54. // TODO: may want to clear from $_transientValues. (Won't be user-visible.)
  55. $this->_values[$k] = $v;
  56. }
  57. if (!self::$permanentAttributes->includes($k))
  58. $this->_unsavedValues->add($k);
  59. }
  60. public function __isset($k)
  61. {
  62. return isset($this->_values[$k]);
  63. }
  64. public function __unset($k)
  65. {
  66. unset($this->_values[$k]);
  67. $this->_transientValues->add($k);
  68. $this->_unsavedValues->discard($k);
  69. }
  70. public function __get($k)
  71. {
  72. if (array_key_exists($k, $this->_values)) {
  73. return $this->_values[$k];
  74. } else if ($this->_transientValues->includes($k)) {
  75. $class = get_class($this);
  76. $attrs = join(', ', array_keys($this->_values));
  77. $message = "Stripe Notice: Undefined property of $class instance: $k. "
  78. . "HINT: The $k attribute was set in the past, however. "
  79. . "It was then wiped when refreshing the object "
  80. . "with the result returned by Stripe's API, "
  81. . "probably as a result of a save(). The attributes currently "
  82. . "available on this object are: $attrs";
  83. error_log($message);
  84. return null;
  85. } else {
  86. $class = get_class($this);
  87. error_log("Stripe Notice: Undefined property of $class instance: $k");
  88. return null;
  89. }
  90. }
  91. // ArrayAccess methods
  92. public function offsetSet($k, $v)
  93. {
  94. $this->$k = $v;
  95. }
  96. public function offsetExists($k)
  97. {
  98. return array_key_exists($k, $this->_values);
  99. }
  100. public function offsetUnset($k)
  101. {
  102. unset($this->$k);
  103. }
  104. public function offsetGet($k)
  105. {
  106. return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
  107. }
  108. public function keys()
  109. {
  110. return array_keys($this->_values);
  111. }
  112. /**
  113. * This unfortunately needs to be public to be used in Util.php
  114. *
  115. * @param Stripe_Object $class
  116. * @param array $values
  117. * @param string|null $apiKey
  118. *
  119. * @return Stripe_Object The object constructed from the given values.
  120. */
  121. public static function scopedConstructFrom($class, $values, $apiKey=null)
  122. {
  123. $obj = new $class(isset($values['id']) ? $values['id'] : null, $apiKey);
  124. $obj->refreshFrom($values, $apiKey);
  125. return $obj;
  126. }
  127. /**
  128. * @param array $values
  129. * @param string|null $apiKey
  130. *
  131. * @return Stripe_Object The object of the same class as $this constructed
  132. * from the given values.
  133. */
  134. public static function constructFrom($values, $apiKey=null)
  135. {
  136. $class = get_class($this);
  137. return self::scopedConstructFrom($class, $values, $apiKey);
  138. }
  139. /**
  140. * Refreshes this object using the provided values.
  141. *
  142. * @param array $values
  143. * @param string $apiKey
  144. * @param boolean $partial Defaults to false.
  145. */
  146. public function refreshFrom($values, $apiKey, $partial=false)
  147. {
  148. $this->_apiKey = $apiKey;
  149. // Wipe old state before setting new. This is useful for e.g. updating a
  150. // customer, where there is no persistent card parameter. Mark those values
  151. // which don't persist as transient
  152. if ($partial)
  153. $removed = new Stripe_Util_Set();
  154. else
  155. $removed = array_diff(array_keys($this->_values), array_keys($values));
  156. foreach ($removed as $k) {
  157. if (self::$permanentAttributes->includes($k))
  158. continue;
  159. unset($this->$k);
  160. }
  161. foreach ($values as $k => $v) {
  162. if (self::$permanentAttributes->includes($k))
  163. continue;
  164. if (self::$nestedUpdatableAttributes->includes($k) && is_array($v))
  165. $this->_values[$k] = Stripe_Object::scopedConstructFrom('Stripe_AttachedObject', $v, $apiKey);
  166. else
  167. $this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey);
  168. $this->_transientValues->discard($k);
  169. $this->_unsavedValues->discard($k);
  170. }
  171. }
  172. /**
  173. * @return array A recursive mapping of attributes to values for this object,
  174. * including the proper value for deleted attributes.
  175. */
  176. public function serializeParameters()
  177. {
  178. $params = array();
  179. if ($this->_unsavedValues) {
  180. foreach ($this->_unsavedValues->toArray() as $k) {
  181. $v = $this->$k;
  182. if ($v === NULL) {
  183. $v = '';
  184. }
  185. $params[$k] = $v;
  186. }
  187. }
  188. // Get nested updates.
  189. foreach (self::$nestedUpdatableAttributes->toArray() as $property) {
  190. if (isset($this->$property) && $this->$property instanceOf Stripe_Object) {
  191. $params[$property] = $this->$property->serializeParameters();
  192. }
  193. }
  194. return $params;
  195. }
  196. // Pretend to have late static bindings, even in PHP 5.2
  197. protected function _lsb($method)
  198. {
  199. $class = get_class($this);
  200. $args = array_slice(func_get_args(), 1);
  201. return call_user_func_array(array($class, $method), $args);
  202. }
  203. protected static function _scopedLsb($class, $method)
  204. {
  205. $args = array_slice(func_get_args(), 2);
  206. return call_user_func_array(array($class, $method), $args);
  207. }
  208. public function __toJSON()
  209. {
  210. if (defined('JSON_PRETTY_PRINT'))
  211. return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
  212. else
  213. return json_encode($this->__toArray(true));
  214. }
  215. public function __toString()
  216. {
  217. return $this->__toJSON();
  218. }
  219. public function __toArray($recursive=false)
  220. {
  221. if ($recursive)
  222. return Stripe_Util::convertStripeObjectToArray($this->_values);
  223. else
  224. return $this->_values;
  225. }
  226. }
  227. Stripe_Object::init();