PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/recurly/base.php

http://github.com/recurly/recurly-client-php
PHP | 327 lines | 301 code | 12 blank | 14 comment | 14 complexity | 0a6d604a1861b0ec0f0e3b3eaeb272ae MD5 | raw file
Possible License(s): MIT, LGPL-2.1
  1. <?php
  2. abstract class Recurly_Base
  3. {
  4. protected $_href;
  5. protected $_client;
  6. protected $_links;
  7. public function __construct($href = null, $client = null)
  8. {
  9. $this->_href = $href;
  10. $this->_client = $client;
  11. $this->_links = array();
  12. }
  13. public function getHref() {
  14. return $this->_href;
  15. }
  16. public function setHref($href) {
  17. $this->_href = $href;
  18. }
  19. /**
  20. * Request the URI, validate the response and return the object.
  21. * @param string Resource URI, if not fully qualified, the base URL will be appended
  22. * @param string Optional client for the request, useful for mocking the client
  23. */
  24. public static function _get($uri, $client = null)
  25. {
  26. if (is_null($client))
  27. $client = new Recurly_Client();
  28. $response = $client->request(Recurly_Client::GET, $uri);
  29. $response->assertValidResponse();
  30. return Recurly_Base::__parseXmlToNewObject($response->body, $client);
  31. }
  32. /**
  33. * Post to the URI, validate the response and return the object.
  34. * @param string Resource URI, if not fully qualified, the base URL will be appended
  35. * @param string Data to post to the URI
  36. * @param string Optional client for the request, useful for mocking the client
  37. */
  38. protected static function _post($uri, $data = null, $client = null)
  39. {
  40. if (is_null($client))
  41. $client = new Recurly_Client();
  42. $response = $client->request(Recurly_Client::POST, $uri, $data);
  43. $response->assertValidResponse();
  44. $object = Recurly_Base::__parseXmlToNewObject($response->body, $client);
  45. $response->assertSuccessResponse($object);
  46. return $object;
  47. }
  48. /**
  49. * Pretty string version of the object
  50. */
  51. public function __toString()
  52. {
  53. $href = $this->getHref();
  54. if (empty($href))
  55. $href = '[new]';
  56. else
  57. $href = '[href=' . $href . ']';
  58. $class = get_class($this);
  59. $values = $this->__valuesString();
  60. return "<$class$href $values>";
  61. }
  62. protected function __valuesString() {
  63. $values = array();
  64. ksort($this->_values);
  65. foreach($this->_values as $key => $value) {
  66. if (is_null($value)) {
  67. $values[] = "$key=null";
  68. } else if (is_int($value)) {
  69. $values[] = "$key=$value";
  70. } else if (is_bool($value)) {
  71. $values[] = "$key=" . ($value ? 'true' : 'false');
  72. } else if ($value instanceof Recurly_Stub) {
  73. $values[] = "$key=$value";
  74. } else if (is_array($value)) {
  75. $innerValues = array();
  76. foreach ($value as $innerValue)
  77. $innerValues[] = strval($innerValue);
  78. $innerValues = implode($innerValues, ', ');
  79. $values[] = "$key=[$innerValues]";
  80. } else if ($value instanceof DateTime) {
  81. $values[] = "$key=\"" . $value->format('Y-m-d H:i:s P') . '"';
  82. } else {
  83. $values[] = "$key=\"$value\"";
  84. }
  85. }
  86. return implode($values, ', ');
  87. }
  88. private function addLink($name, $href, $method){
  89. $this->_links[$name] = new Recurly_Link($name, $href, $method);
  90. }
  91. /* ******************************************************
  92. ** XML Parser
  93. ****************************************************** */
  94. /**
  95. * Mapping of XML node to PHP object name
  96. */
  97. static $class_map = array(
  98. 'account' => 'Recurly_Account',
  99. 'accounts' => 'Recurly_AccountList',
  100. 'add_on' => 'Recurly_AddOn',
  101. 'add_ons' => 'Recurly_AddOnList',
  102. 'billing_info' => 'Recurly_BillingInfo',
  103. 'adjustment' => 'Recurly_Adjustment',
  104. 'adjustments' => 'Recurly_AdjustmentList',
  105. 'coupon' => 'Recurly_Coupon',
  106. 'currency' => 'Recurly_Currency',
  107. 'details' => 'array',
  108. 'discount_in_cents' => 'Recurly_CurrencyList',
  109. 'error' => 'Recurly_FieldError',
  110. 'errors' => 'Recurly_ErrorList',
  111. 'invoice' => 'Recurly_Invoice',
  112. 'invoices' => 'Recurly_InvoiceList',
  113. 'line_items' => 'array',
  114. 'plan' => 'Recurly_Plan',
  115. 'plans' => 'Recurly_PlanList',
  116. 'plan_code' => 'string',
  117. 'plan_codes' => 'array',
  118. 'pending_subscription' => 'Recurly_Subscription',
  119. 'redemption' => 'Recurly_CouponRedemption',
  120. 'setup_fee_in_cents' => 'Recurly_CurrencyList',
  121. 'subscription' => 'Recurly_Subscription',
  122. 'subscriptions' => 'Recurly_SubscriptionList',
  123. 'subscription_add_ons' => 'array',
  124. 'subscription_add_on' => 'Recurly_SubscriptionAddOn',
  125. 'transaction' => 'Recurly_Transaction',
  126. 'transactions' => 'Recurly_TransactionList',
  127. 'transaction_error' => 'Recurly_TransactionError',
  128. 'unit_amount_in_cents' => 'Recurly_CurrencyList'
  129. );
  130. protected static function __parseXmlToNewObject($xml, $client=null) {
  131. $dom = new DOMDocument();
  132. if (!$dom->loadXML($xml, LIBXML_NOBLANKS)) return null;
  133. $rootNode = $dom->documentElement;
  134. $obj = Recurly_Resource::__createNodeObject($rootNode);
  135. Recurly_Resource::__parseXmlToObject($rootNode->firstChild, $obj);
  136. $obj->_client = $client;
  137. return $obj;
  138. }
  139. protected function __parseXmlToUpdateObject($xml)
  140. {
  141. $dom = new DOMDocument();
  142. if (!$dom->loadXML($xml, LIBXML_NOBLANKS)) return null;
  143. $rootNode = $dom->documentElement;
  144. if ($rootNode->nodeName == $this->getNodeName()) {
  145. // update the current object
  146. Recurly_Resource::__parseXmlToObject($rootNode->firstChild, $this);
  147. } else if ($rootNode->nodeName == 'errors') {
  148. // add element to existing object
  149. Recurly_Resource::__parseXmlToObject($rootNode->firstChild, $this->_errors);
  150. }
  151. $this->updateErrorAttributes();
  152. }
  153. protected static function __parseXmlToObject($node, &$object)
  154. {
  155. while ($node) {
  156. //print "Node: {$node->nodeType} -- {$node->nodeName}\n";
  157. if ($node->nodeType == XML_TEXT_NODE) {
  158. if ($node->wholeText != null) {
  159. $text = trim($node->wholeText);
  160. if (!empty($text))
  161. $object->description = $text;
  162. }
  163. } else if ($node->nodeType == XML_ELEMENT_NODE) {
  164. $nodeName = str_replace("-", "_", $node->nodeName);
  165. if ($object instanceof Recurly_Pager) {
  166. $new_obj = Recurly_Resource::__createNodeObject($node);
  167. if (!is_null($new_obj)) {
  168. Recurly_Resource::__parseXmlToObject($node->firstChild, $new_obj);
  169. $object->_objects[] = $new_obj;
  170. }
  171. $node = $node->nextSibling;
  172. continue;
  173. } else if ($object instanceof Recurly_ErrorList) {
  174. if ($nodeName == 'error') {
  175. $object[] = Recurly_Resource::parseErrorNode($node);
  176. $node = $node->nextSibling;
  177. continue;
  178. }
  179. } else if (is_array($object)) {
  180. if ($nodeName == 'error') {
  181. $object[] = Recurly_Resource::parseErrorNode($node);
  182. $node = $node->nextSibling;
  183. continue;
  184. }
  185. $new_obj = Recurly_Resource::__createNodeObject($node);
  186. if (!is_null($new_obj)) {
  187. if (is_object($new_obj) || is_array($new_obj))
  188. Recurly_Resource::__parseXmlToObject($node->firstChild, $new_obj);
  189. $object[] = $new_obj;
  190. }
  191. $node = $node->nextSibling;
  192. continue;
  193. }
  194. $numChildren = $node->childNodes->length;
  195. if ($numChildren == 0) {
  196. // No children, we might have a link
  197. $href = $node->getAttribute('href');
  198. if (!empty($href)) {
  199. if ($nodeName == 'a') {
  200. $linkName = $node->getAttribute('name');
  201. $method = $node->getAttribute('method');
  202. $object->addLink($linkName, $href, $method);
  203. } else {
  204. if (!is_object($object))
  205. $object->$nodeName = new Recurly_Stub($nodeName, $href);
  206. else
  207. $object->$nodeName = new Recurly_Stub($nodeName, $href, $object->_client);
  208. }
  209. }
  210. } else if ($node->firstChild->nodeType == XML_ELEMENT_NODE) {
  211. // has element children, drop in and continue parsing
  212. $new_obj = Recurly_Resource::__createNodeObject($node);
  213. if (!is_null($new_obj))
  214. $object->$nodeName = Recurly_Resource::__parseXmlToObject($node->firstChild, $new_obj);
  215. } else {
  216. // we have a single text child
  217. if ($node->hasAttribute('nil')) {
  218. $object->$nodeName = null;
  219. } else {
  220. switch ($node->getAttribute('type')) {
  221. case 'boolean':
  222. $object->$nodeName = ($node->nodeValue == 'true');
  223. break;
  224. case 'date':
  225. case 'datetime':
  226. $object->$nodeName = new DateTime($node->nodeValue);
  227. break;
  228. case 'float':
  229. $object->$nodeName = (float)$node->nodeValue;
  230. break;
  231. case 'integer':
  232. $object->$nodeName = (int)$node->nodeValue;
  233. break;
  234. case 'array':
  235. $object->$nodeName = array();
  236. break;
  237. default:
  238. $object->$nodeName = $node->nodeValue;
  239. }
  240. }
  241. }
  242. }
  243. $node = $node->nextSibling;
  244. }
  245. if (isset($object->_unsavedKeys))
  246. $object->_unsavedKeys = array();
  247. return $object;
  248. }
  249. private static function parseErrorNode($node)
  250. {
  251. $error = new Recurly_FieldError();
  252. $error->field = $node->getAttribute('field');
  253. $error->symbol = $node->getAttribute('symbol');
  254. $error->description = $node->firstChild->wholeText;
  255. return $error;
  256. }
  257. private static function __createNodeObject($node)
  258. {
  259. $nodeName = str_replace("-", "_", $node->nodeName);
  260. if (!array_key_exists($nodeName, Recurly_Resource::$class_map)) {
  261. return null; // Unknown element
  262. }
  263. $node_class = Recurly_Resource::$class_map[$nodeName];
  264. if ($node_class == null)
  265. return new Recurly_Object();
  266. else if ($node_class == 'array')
  267. return array();
  268. else if ($node_class == 'string')
  269. return $node->firstChild->wholeText;
  270. else {
  271. if ($node_class == 'Recurly_CurrencyList') {
  272. $new_obj = new $node_class($nodeName);
  273. } else
  274. $new_obj = new $node_class();
  275. $href = $node->getAttribute('href');
  276. if (!empty($href))
  277. $new_obj->setHref($href);
  278. else if ($new_obj instanceof Recurly_Pager) {
  279. $new_obj->_count = $node->childNodes->length;
  280. }
  281. return $new_obj;
  282. }
  283. }
  284. }
  285. // In case node_class is not specified.
  286. class Recurly_Object {}