PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/PodioObject.php

http://github.com/podio/podio-php
PHP | 357 lines | 334 code | 14 blank | 9 comment | 43 complexity | ab2a017ba7b8872e4a7de65d2d54bc7e MD5 | raw file
  1. <?php
  2. class PodioObject
  3. {
  4. private $__attributes = array();
  5. private $__belongs_to;
  6. private $__properties = array();
  7. private $__relationships = array();
  8. protected $__id_column;
  9. public function init($default_attributes = array())
  10. {
  11. if (is_int($default_attributes)) {
  12. $default_attributes = array('id' => $default_attributes);
  13. }
  14. if (is_string($default_attributes)) {
  15. $default_attributes = array('external_id' => $default_attributes);
  16. }
  17. if (!is_array($default_attributes)) {
  18. $default_attributes = array();
  19. }
  20. $has_api_values = !empty($default_attributes['__api_values']);
  21. // Create object instance from attributes
  22. foreach ($this->__properties as $name => $property) {
  23. if (isset($property['options']['id'])) {
  24. $this->__id_column = $name;
  25. if (array_key_exists('id', $default_attributes)) {
  26. $this->id = $default_attributes['id'];
  27. }
  28. }
  29. if (array_key_exists($name, $default_attributes)) {
  30. // Special handling for PodioItemField values property so
  31. // we can construct using both the API format when receiving responses
  32. // and the much simpler podio-php format when constructing manually.
  33. if ($name == 'values' && !$has_api_values) {
  34. $this->values = $default_attributes[$name];
  35. } else {
  36. $this->set_attribute($name, $default_attributes[$name]);
  37. }
  38. }
  39. }
  40. if ($this->__relationships) {
  41. foreach ($this->__relationships as $name => $type) {
  42. if (array_key_exists($name, $default_attributes)) {
  43. $property = $this->__properties[$name];
  44. $class_name = 'Podio'.$property['type'];
  45. if ($type == 'has_one') {
  46. $child = is_object($default_attributes[$name]) ? $default_attributes[$name] : new $class_name($default_attributes[$name]);
  47. $child->add_relationship($this, $name);
  48. $this->set_attribute($name, $child);
  49. } elseif ($type == 'has_many' && is_array($default_attributes[$name])) {
  50. // Special handling for ItemField and AppField.
  51. // We need to create collection of the right type
  52. if ($class_name == 'PodioItemField') {
  53. $collection_class = 'PodioItemFieldCollection';
  54. $values = $default_attributes[$name];
  55. // Make sure we pass along info on whether the values property
  56. // contains API style values or not
  57. $collection = new $collection_class($values, $has_api_values);
  58. } elseif ($class_name == 'PodioAppField') {
  59. $collection_class = 'PodioAppFieldCollection';
  60. $values = $default_attributes[$name];
  61. $collection = new $collection_class($values);
  62. } else {
  63. $collection_class = 'PodioCollection';
  64. $values = array();
  65. foreach ($default_attributes[$name] as $value) {
  66. $child = is_object($value) ? $value : new $class_name($value);
  67. $values[] = $child;
  68. }
  69. $collection = new $collection_class($values);
  70. }
  71. $collection->add_relationship($this, $name);
  72. $this->set_attribute($name, $collection);
  73. }
  74. }
  75. }
  76. }
  77. }
  78. public function __set($name, $value)
  79. {
  80. if ($name == 'id' && !empty($this->__id_column)) {
  81. return $this->set_attribute($this->__id_column, $value);
  82. }
  83. return $this->set_attribute($name, $value);
  84. }
  85. public function __get($name)
  86. {
  87. if ($name == 'id' && !empty($this->__id_column)) {
  88. return empty($this->__attributes[$this->__id_column]) ? null : $this->__attributes[$this->__id_column];
  89. }
  90. if ($this->has_attribute($name)) {
  91. // Create DateTime object if necessary
  92. if ($this->has_property($name) && ($this->__properties[$name]['type'] == 'datetime' || $this->__properties[$name]['type'] == 'date')) {
  93. $tz = new DateTimeZone('UTC');
  94. return DateTime::createFromFormat($this->date_format_for_property($name), $this->__attributes[$name], $tz);
  95. }
  96. return $this->__attributes[$name];
  97. }
  98. }
  99. public function __isset($name)
  100. {
  101. return isset($this->__attributes[$name]);
  102. }
  103. public function __unset($name)
  104. {
  105. unset($this->__attributes[$name]);
  106. }
  107. public function __toString()
  108. {
  109. return print_r($this->as_json(false), true);
  110. }
  111. public function date_format_for_property($name)
  112. {
  113. if ($this->has_property($name)) {
  114. if ($this->__properties[$name]['type'] == 'datetime') {
  115. return 'Y-m-d H:i:s';
  116. } elseif ($this->__properties[$name]['type'] == 'date') {
  117. return 'Y-m-d';
  118. }
  119. }
  120. }
  121. public function relationship()
  122. {
  123. return $this->__belongs_to;
  124. }
  125. public function add_relationship($instance, $property = 'fields')
  126. {
  127. $this->__belongs_to = array('property' => $property, 'instance' => $instance);
  128. }
  129. protected function set_attribute($name, $value)
  130. {
  131. if ($this->has_property($name)) {
  132. $property = $this->__properties[$name];
  133. switch ($property['type']) {
  134. case 'integer':
  135. $this->__attributes[$name] = $value ? (int)$value : null;
  136. break;
  137. case 'boolean':
  138. $this->__attributes[$name] = null;
  139. if ($value === true || $value === false) {
  140. $this->__attributes[$name] = $value;
  141. } elseif ($value) {
  142. $this->__attributes[$name] = in_array(trim(strtolower($value)), array('true', 1, 'yes'));
  143. }
  144. break;
  145. case 'datetime':
  146. case 'date':
  147. if (is_a($value, 'DateTime')) {
  148. $this->__attributes[$name] = $value->format($this->date_format_for_property($name));
  149. } else {
  150. $this->__attributes[$name] = $value;
  151. }
  152. break;
  153. case 'string':
  154. if (is_array($value)) {
  155. $value = join(', ', $value);
  156. }
  157. $this->__attributes[$name] = $value ? (string)$value : null;
  158. break;
  159. case 'array':
  160. case 'hash':
  161. $this->__attributes[$name] = $value ? (array)$value : array();
  162. break;
  163. default:
  164. $this->__attributes[$name] = $value;
  165. }
  166. return true;
  167. }
  168. throw new PodioDataIntegrityError("Attribute cannot be assigned. Property '{$name}' doesn't exist.");
  169. }
  170. public static function listing($response_or_attributes)
  171. {
  172. if ($response_or_attributes) {
  173. if (is_object($response_or_attributes) && get_class($response_or_attributes) == 'PodioResponse') {
  174. $body = $response_or_attributes->json_body();
  175. } else {
  176. $body = $response_or_attributes;
  177. }
  178. $list = array();
  179. foreach ($body as $attributes) {
  180. $class_name = get_called_class();
  181. $list[] = new $class_name(array_merge($attributes, array('__api_values' => true)));
  182. }
  183. return $list;
  184. }
  185. }
  186. public static function member($response)
  187. {
  188. if ($response) {
  189. $class_name = get_called_class();
  190. return new $class_name(array_merge($response instanceof PodioResponse ? $response->json_body() : $response, array('__api_values' => true)));
  191. }
  192. }
  193. public static function collection($response, $collection_type = "PodioCollection")
  194. {
  195. if ($response) {
  196. $body = $response->json_body();
  197. $list = array();
  198. if (isset($body['items'])) {
  199. foreach ($body['items'] as $attributes) {
  200. $class_name = get_called_class();
  201. $list[] = new $class_name(array_merge($attributes, array('__api_values' => true)));
  202. }
  203. }
  204. return new $collection_type($list, $body['filtered'], $body['total']);
  205. }
  206. }
  207. public function can($right)
  208. {
  209. if ($this->has_property('rights')) {
  210. return $this->has_attribute('rights') && in_array($right, $this->rights);
  211. }
  212. return false;
  213. }
  214. public function has_attribute($name)
  215. {
  216. return array_key_exists($name, $this->__attributes);
  217. }
  218. public function has_property($name)
  219. {
  220. return array_key_exists($name, $this->__properties);
  221. }
  222. public function has_relationship($name)
  223. {
  224. return array_key_exists($name, $this->__relationships);
  225. }
  226. public function properties()
  227. {
  228. return $this->__properties;
  229. }
  230. public function relationships()
  231. {
  232. return $this->__relationships;
  233. }
  234. /**
  235. * Raw access to attributes. Only used for unit testing. Do not use.
  236. */
  237. public function __attribute($name)
  238. {
  239. return $this->__attributes[$name];
  240. }
  241. // Define a property on this object
  242. public function property($name, $type, $options = array())
  243. {
  244. if (!$this->has_property($name)) {
  245. $this->__properties[$name] = array('type' => $type, 'options' => $options);
  246. }
  247. }
  248. public function has_one($name, $class_name, $options = array())
  249. {
  250. $this->property($name, $class_name, $options);
  251. if (!$this->has_relationship($name)) {
  252. $this->__relationships[$name] = 'has_one';
  253. }
  254. }
  255. public function has_many($name, $class_name, $options = array())
  256. {
  257. $this->property($name, $class_name, $options);
  258. if (!$this->has_relationship($name)) {
  259. $this->__relationships[$name] = 'has_many';
  260. }
  261. }
  262. public function as_json($encoded = true)
  263. {
  264. $result = array();
  265. foreach ($this->__properties as $name => $property) {
  266. if (!$this->has_relationship($name) && $this->has_attribute($name) && !is_null($this->__attributes[$name])) {
  267. $result[$name] = $this->__attributes[$name];
  268. }
  269. }
  270. foreach ($this->__relationships as $name => $type) {
  271. if ($type == 'has_one') {
  272. $target_name = $name;
  273. if (!empty($this->__properties[$name]['options']['json_target'])) {
  274. $target_name = $this->__properties[$name]['options']['json_target'];
  275. }
  276. if ($this->has_attribute($name)) {
  277. if (!empty($this->__properties[$name]['options']['json_value'])) {
  278. $result[$target_name] = $this->__attributes[$name]->{$this->__properties[$name]['options']['json_value']};
  279. } elseif (is_a($this->__attributes[$name], 'PodioFieldCollection')) {
  280. foreach ($this->__attributes[$name] as $field) {
  281. // Only use external_id for item fields
  282. $key = $field->external_id && is_a($this->__attributes[$name], 'PodioItemFieldCollection') ? $field->external_id : $field->id;
  283. $list[$key] = $field->as_json(false);
  284. }
  285. $result[$name] = $list;
  286. } elseif (is_object($this->__attributes[$name]) && get_class($this->__attributes[$name]) == 'PodioReference') {
  287. $result['ref_type'] = $this->__attributes[$name]->type;
  288. $result['ref_id'] = $this->__attributes[$name]->id;
  289. } else {
  290. $child = $this->__attributes[$name]->as_json(false);
  291. if ($child) {
  292. $result[$target_name] = $child;
  293. }
  294. }
  295. }
  296. } elseif ($type == 'has_many') {
  297. if ($this->has_attribute($name)) {
  298. $list = array();
  299. foreach ($this->__attributes[$name] as $item) {
  300. if (!empty($this->__properties[$name]['options']['json_value'])) {
  301. $list[] = $item->{$this->__properties[$name]['options']['json_value']};
  302. }
  303. // TODO: This really should be moved to PodioCollection (should implement as_json)
  304. // and PodioItemFieldCollection for the special case
  305. elseif (get_class($this->__attributes[$name]) === 'PodioItemFieldCollection') {
  306. $key = $item->external_id ? $item->external_id : (string)$item->field_id;
  307. $list[$key] = $item->as_json(false);
  308. } else {
  309. $list[] = $item->as_json(false);
  310. }
  311. }
  312. if ($list) {
  313. if (!empty($this->__properties[$name]['options']['json_target'])) {
  314. $result[$this->__properties[$name]['options']['json_target']] = $list;
  315. } else {
  316. $result[$name] = $list;
  317. }
  318. }
  319. }
  320. }
  321. }
  322. if ($result) {
  323. return $encoded ? json_encode($result) : $result;
  324. }
  325. return null;
  326. }
  327. }