PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/models/PodioItemField.php

https://github.com/cbcolvard/podio-php
PHP | 563 lines | 441 code | 33 blank | 89 comment | 50 complexity | 523897254743845f7e54e5f0695cef2b MD5 | raw file
  1. <?php
  2. /**
  3. * @see https://developers.podio.com/doc/items
  4. */
  5. class PodioItemField extends PodioObject {
  6. public function __construct($attributes = array(), $force_type = null) {
  7. $this->property('field_id', 'integer', array('id' => true));
  8. $this->property('type', 'string');
  9. $this->property('external_id', 'string');
  10. $this->property('label', 'string');
  11. $this->property('values', 'array');
  12. $this->property('config', 'hash');
  13. $this->init($attributes);
  14. $this->set_type_from_class_name();
  15. }
  16. /**
  17. * Saves the value of the field
  18. */
  19. public function save($options = array()) {
  20. if (!$this->__belongs_to) {
  21. throw new PodioMissingRelationshipError('{"error_description":"Field is missing relationship to item"}', null, null);
  22. }
  23. if (!$this->id) {
  24. throw new PodioDataIntegrityError('Field must have id set.');
  25. }
  26. $attributes = $this->as_json(false);
  27. return self::update($this->__belongs_to['instance']->id, $this->id, $attributes, $options);
  28. }
  29. /**
  30. * Adds a relationship to an item.
  31. */
  32. function add_relationship($item) {
  33. $this->__belongs_to = array('property' => 'fields', 'instance' => $item);
  34. }
  35. /**
  36. * Overwrites normal as_json to use api_friendly_values
  37. */
  38. public function as_json($encoded = true) {
  39. $result = $this->api_friendly_values();
  40. return $encoded ? json_encode($result) : $result;
  41. }
  42. /**
  43. * Set the value of the field
  44. */
  45. public function set_value($values) {
  46. if (!$values) {
  47. $this->values = array();
  48. }
  49. else {
  50. switch ($this->type) {
  51. case 'contact': // profile_id
  52. case 'app': // item_id
  53. case 'image': // file_id
  54. case 'video': // file_id
  55. case 'file': // file_id
  56. case 'question': // id
  57. case 'category': // id
  58. $list = array();
  59. $id_key = 'file_id';
  60. if (in_array($this->type, array('category', 'question'))) {
  61. $id_key = 'id';
  62. }
  63. elseif ($this->type == 'app') {
  64. $id_key = 'item_id';
  65. }
  66. elseif ($this->type == 'contact') {
  67. $id_key = 'profile_id';
  68. }
  69. // Ensure that we have an array of values
  70. if (!is_array($values) || (is_array($values) && !empty($values[$id_key]))) {
  71. $values = array($values);
  72. }
  73. $this->values = array_map(function($value) use ($id_key) {
  74. if (is_object($value)) {
  75. return array('value' => array($id_key => (int)$value->{$id_key}));
  76. }
  77. elseif (is_array($value)) {
  78. return array('value' => array($id_key => (int)$value[$id_key]));
  79. }
  80. else {
  81. return array('value' => array($id_key => (int)$value));
  82. }
  83. }, $values);
  84. break;
  85. // Single value fields with integer value
  86. case 'progress':
  87. case 'duration':
  88. $this->values = is_array($values) ? array(array('value' => (int)$values[0])) : array(array('value' => (int)$values));
  89. break;
  90. // Single value fields with string value
  91. case 'text':
  92. case 'number':
  93. case 'money':
  94. case 'state':
  95. case 'calculation':
  96. default:
  97. $this->values = is_array($values) ? array(array('value' => $values[0])) : array(array('value' => $values));
  98. break;
  99. }
  100. }
  101. }
  102. /**
  103. * Returns API friendly values for item field for use when saving item
  104. */
  105. public function api_friendly_values() {
  106. if (!$this->values) {
  107. return array();
  108. }
  109. switch ($this->type) {
  110. case 'contact': // profile_id
  111. case 'app': // item_id
  112. case 'question': // id
  113. case 'category': //id
  114. case 'image': // file_id
  115. case 'video': // file_id
  116. case 'file': // file_id
  117. $list = array();
  118. foreach ($this->values as $value) {
  119. if (!empty($value['value']['id'])) {
  120. $list[] = $value['value']['id'];
  121. }
  122. elseif (!empty($value['value']['file_id'])) {
  123. $list[] = $value['value']['file_id'];
  124. }
  125. elseif (!empty($value['value']['item_id'])) {
  126. $list[] = $value['value']['item_id'];
  127. }
  128. elseif (!empty($value['value']['profile_id'])) {
  129. $list[] = $value['value']['profile_id'];
  130. }
  131. }
  132. return $list;
  133. break;
  134. case 'embed':
  135. $list = array();
  136. foreach ($this->values as $value) {
  137. $list[] = array('embed' => $value['embed']['embed_id'], 'file' => (!empty($value['file']) ? $value['file']['file_id'] : null) );
  138. }
  139. return $list;
  140. break;
  141. case 'location':
  142. $list = array();
  143. foreach ($this->values as $value) {
  144. $list[] = $value['value'];
  145. }
  146. return $list;
  147. break;
  148. case 'date':
  149. return array('start' => $this->values[0]['start'], 'end' => $this->values[0]['end']);
  150. break;
  151. case 'text':
  152. case 'number':
  153. case 'money':
  154. case 'progress':
  155. case 'state':
  156. case 'duration':
  157. case 'calculation':
  158. default:
  159. return $this->values;
  160. break;
  161. }
  162. }
  163. /**
  164. * Displays a human-friendly value for the field
  165. */
  166. public function humanized_value() {
  167. return $this->values[0]['value'];
  168. }
  169. /**
  170. * @see https://developers.podio.com/doc/items/update-item-field-values-22367
  171. */
  172. public static function update($item_id, $field_id, $attributes = array(), $options = array()) {
  173. $url = Podio::url_for_post_with_options("/item/{$item_id}/value/{$field_id}", $options);
  174. return Podio::put($url, $attributes)->json_body();
  175. }
  176. /**
  177. * @see https://developers.podio.com/doc/calendar/get-item-field-calendar-as-ical-10195681
  178. */
  179. public static function ical($item_id, $field_id) {
  180. return Podio::get("/calendar/item/{$item_id}/field/{$field_id}/ics/")->body;
  181. }
  182. /**
  183. * @see https://developers.podio.com/doc/calendar/get-item-field-calendar-as-ical-10195681
  184. */
  185. public static function ical_field($item_id, $field_id) {
  186. return Podio::get("/calendar/item/{$item_id}/field/{$field_id}/ics/")->body;
  187. }
  188. public function set_type_from_class_name() {
  189. switch (get_class($this)) {
  190. case 'PodioTextItemField':
  191. $this->type = 'text';
  192. break;
  193. case 'PodioEmbedItemField':
  194. $this->type = 'embed';
  195. break;
  196. case 'PodioLocationItemField':
  197. $this->type = 'location';
  198. break;
  199. case 'PodioDateItemField':
  200. $this->type = 'date';
  201. break;
  202. case 'PodioContactItemField':
  203. $this->type = 'contact';
  204. break;
  205. case 'PodioAppItemField':
  206. $this->type = 'app';
  207. break;
  208. case 'PodioQuestionItemField':
  209. $this->type = 'question';
  210. break;
  211. case 'PodioCategoryItemField':
  212. $this->type = 'category';
  213. break;
  214. case 'PodioImageItemField':
  215. $this->type = 'image';
  216. break;
  217. case 'PodioVideoItemField':
  218. $this->type = 'video';
  219. break;
  220. case 'PodioFileItemField':
  221. $this->type = 'file';
  222. break;
  223. case 'PodioNumberItemField':
  224. $this->type = 'number';
  225. break;
  226. case 'PodioProgressItemField':
  227. $this->type = 'progress';
  228. break;
  229. case 'PodioStateItemField':
  230. $this->type = 'state';
  231. break;
  232. case 'PodioDurationItemField':
  233. $this->type = 'duration';
  234. break;
  235. case 'PodioCalculationItemField':
  236. $this->type = 'calculation';
  237. break;
  238. case 'PodioMoneyItemField':
  239. $this->type = 'money';
  240. break;
  241. default:
  242. break;
  243. }
  244. }
  245. }
  246. class PodioTextItemField extends PodioItemField {
  247. public function humanized_value() {
  248. return strip_tags($this->values[0]['value']);
  249. }
  250. }
  251. class PodioEmbedItemField extends PodioItemField {
  252. /**
  253. * Provides a list list of PodioEmbed and PodioFile objects for the field.
  254. * This read-only. Changing the values of the PodioItem objects
  255. * will not update the values of the PodioItemField.
  256. */
  257. public function embeds() {
  258. $list = array();
  259. foreach ($this->values as $delta => $value) {
  260. $list[] = array('delta' => $delta, 'embed' => new PodioEmbed($value['embed']), 'file' => ($value['file'] ? new PodioFile($value['file']) : null));
  261. }
  262. return $list;
  263. }
  264. public function humanized_value() {
  265. return join('; ', array_map(function($value){
  266. return $value['embed']['original_url'];
  267. }, $this->values));
  268. }
  269. public function set_value($values) {
  270. $this->values = array();
  271. if ($values) {
  272. // Ensure that we have an array of values
  273. if (is_object($values) || (is_array($values) && !empty($values['embed']))) {
  274. $values = array($values);
  275. }
  276. $this->values = array_map(function($value) {
  277. if (is_object($value)) {
  278. return array('embed' => array('embed_id' => $value->id), 'file' => array('file_id' => $value->files ? $value->files[0]->id : null));
  279. }
  280. return $value;
  281. }, $values);
  282. }
  283. }
  284. }
  285. class PodioLocationItemField extends PodioItemField {
  286. public function set_value($values) {
  287. $this->values = array();
  288. if ($values) {
  289. if (is_array($values)) {
  290. $formatted_values = array_map(function($value){
  291. return array('value' => $value);
  292. }, $values);
  293. $this->values = $formatted_values;
  294. }
  295. else {
  296. $this->values = array(array('value' => $values));
  297. }
  298. }
  299. }
  300. public function humanized_value() {
  301. return join('; ', array_map(function($value){
  302. return $value['value'];
  303. }, $this->values));
  304. }
  305. }
  306. class PodioDateItemField extends PodioItemField {
  307. public function __construct($attributes = array()) {
  308. parent::__construct($attributes, 'date');
  309. }
  310. public function set_value($values) {
  311. $this->values = array();
  312. if ($values) {
  313. $this->values = array($values);
  314. }
  315. }
  316. public function humanized_value() {
  317. $value = $this->values[0];
  318. // Remove seconds from start and end times since they are always '00' anyway.
  319. if (!empty($value['start_time'])) {
  320. $value['start_time'] = substr($value['start_time'], 0, strrpos($value['start_time'], ':'));
  321. }
  322. if (!empty($value['end_time'])) {
  323. $value['end_time'] = substr($value['end_time'], 0, strrpos($value['end_time'], ':'));
  324. }
  325. // Variants:
  326. // Same date
  327. // 2012-12-12
  328. // 2012-12-12 14:00
  329. // 2012-12-12 14:00 - 15:00
  330. // Different dates
  331. // 2012-12-12 - 2012-12-14
  332. // 2012-12-12 14:00 - 2012-12-14
  333. // 2012-12-12 14:00 - 2012-12-12 15:00
  334. if (empty($value['end_date']) || $value['start_date'] == $value['end_date']) {
  335. if (!empty($value['start_time']) && !empty($value['end_time']) && $value['start_time'] != $value['end_time']) {
  336. return "{$value['start_date']} {$value['start_time']}-{$value['end_time']}";
  337. }
  338. elseif (!empty($value['start_time']) && (empty($value['end_time']) || $value['start_time'] == $value['end_time'])) {
  339. return "{$value['start_date']} {$value['start_time']}";
  340. }
  341. else {
  342. return "{$value['start_date']}";
  343. }
  344. }
  345. else {
  346. if (!empty($value['start_time']) && !empty($value['end_time']) && $value['end_time'] != '00:00') {
  347. return "{$value['start_date']} {$value['start_time']} - {$value['end_date']} {$value['end_time']}";
  348. }
  349. elseif (!empty($value['end_time']) || $value['end_time'] == '00:00') {
  350. return "{$value['start_date']} {$value['start_time']} - {$value['end_date']}";
  351. }
  352. else {
  353. return "{$value['start_date']} - {$value['end_date']}";
  354. }
  355. }
  356. }
  357. // TODO: Set start and end date and times easily
  358. }
  359. class PodioContactItemField extends PodioItemField {
  360. /**
  361. * Provides a list a PodioContact objects for the PodioItemField
  362. * This read-only. Changing the values of the PodioContact objects
  363. * will not update the values of the PodioItemField.
  364. */
  365. public function contacts() {
  366. return array_map(function($value){
  367. return new PodioFile($value['value']);
  368. }, $this->values);
  369. }
  370. public function humanized_value() {
  371. return join('; ', array_map(function($value){
  372. return $value['value']['name'];
  373. }, $this->values));
  374. }
  375. }
  376. class PodioAppItemField extends PodioItemField {
  377. /**
  378. * Provides a list a PodioItem objects for the PodioItemField
  379. * This read-only. Changing the values of the PodioItem objects
  380. * will not update the values of the PodioItemField.
  381. */
  382. public function items() {
  383. return array_map(function($value){
  384. return new PodioItem($value['value']);
  385. }, $this->values);
  386. }
  387. public function humanized_value() {
  388. return join('; ', array_map(function($value){
  389. return $value['value']['title'];
  390. }, $this->values));
  391. }
  392. }
  393. class PodioQuestionItemField extends PodioItemField {
  394. public function humanized_value() {
  395. return join('; ', array_map(function($value){
  396. return $value['value']['text'];
  397. }, $this->values));
  398. }
  399. }
  400. class PodioCategoryItemField extends PodioItemField {
  401. public function humanized_value() {
  402. return join('; ', array_map(function($value){
  403. return $value['value']['text'];
  404. }, $this->values));
  405. }
  406. }
  407. class PodioAssetItemField extends PodioItemField {
  408. /**
  409. * Provides a list a PodioFile objects for the PodioItemField
  410. * This read-only. Changing the values of the PodioFile objects
  411. * will not update the values of the PodioItemField.
  412. */
  413. public function files() {
  414. return array_map(function($value){
  415. return new PodioContact($value['value']);
  416. }, $this->values);
  417. }
  418. }
  419. class PodioImageItemField extends PodioAssetItemField {
  420. public function humanized_value() {
  421. return join('; ', array_map(function($value){
  422. return $value['value']['name'];
  423. }, $this->values));
  424. }
  425. }
  426. class PodioVideoItemField extends PodioAssetItemField {
  427. public function humanized_value() {
  428. return join('; ', array_map(function($value){
  429. return $value['value']['name'];
  430. }, $this->values));
  431. }
  432. }
  433. class PodioFileItemField extends PodioAssetItemField {
  434. public function humanized_value() {
  435. return join('; ', array_map(function($value){
  436. return $value['value']['name'];
  437. }, $this->values));
  438. }
  439. }
  440. class PodioNumberItemField extends PodioItemField {
  441. public function humanized_value() {
  442. return rtrim(rtrim(number_format($this->values[0]['value'], 4, '.', ''), '0'), '.');
  443. }
  444. }
  445. class PodioProgressItemField extends PodioItemField {
  446. public function humanized_value() {
  447. return $this->values[0]['value'].'%';
  448. }
  449. }
  450. class PodioStateItemField extends PodioItemField {}
  451. class PodioDurationItemField extends PodioItemField {
  452. /**
  453. * Duration in seconds
  454. */
  455. public function duration() {
  456. return $this->values[0]['value'];
  457. }
  458. /**
  459. * Hours of the duration
  460. */
  461. public function hours() {
  462. return floor($this->values[0]['value']/3600);
  463. }
  464. /**
  465. * Minutes of the duration
  466. */
  467. public function minutes() {
  468. return (($this->values[0]['value']/60)%60);
  469. }
  470. /**
  471. * Seconds of the duration
  472. */
  473. public function seconds() {
  474. return ($this->values[0]['value']%60);
  475. }
  476. }
  477. class PodioCalculationItemField extends PodioItemField {
  478. public function humanized_value() {
  479. return rtrim(rtrim(number_format($this->values[0]['value'], 4, '.', ''), '0'), '.');
  480. }
  481. }
  482. class PodioMoneyItemField extends PodioItemField {
  483. /**
  484. * Currency part of the value
  485. */
  486. public function currency() {
  487. if (!empty($this->values)) {
  488. return $this->values[0]['currency'];
  489. }
  490. }
  491. /**
  492. * Set the currency value.
  493. */
  494. public function set_currency($currency) {
  495. $value = $this->values[0]['value'] ? $this->values[0]['value'] : 0;
  496. $this->set_attribute('values', array(array('currency' => $currency, 'value' => $value)));
  497. }
  498. /**
  499. * Amount part of the value
  500. */
  501. public function amount() {
  502. if (!empty($this->values)) {
  503. return $this->values[0]['value'];
  504. }
  505. }
  506. /**
  507. * Set the amount.
  508. */
  509. public function set_amount($amount) {
  510. $currency = $this->values[0]['currency'] ? $this->values[0]['currency'] : '';
  511. $this->set_attribute('values', array(array('currency' => $currency, 'value' => $amount)));
  512. }
  513. public function humanized_value() {
  514. $amount = number_format($this->values[0]['value'], 2, '.', '');
  515. switch ($this->values[0]['currency']) {
  516. case 'USD':
  517. $currency = '$';
  518. case 'EUR':
  519. $currency = '€';
  520. break;
  521. case 'GBP':
  522. $currency = 'ÂŁ';
  523. break;
  524. default:
  525. $currency = $this->values[0]['currency'].' ';
  526. break;
  527. }
  528. return $currency.$amount;
  529. }
  530. }