/lib/PodioObject.php
PHP | 357 lines | 334 code | 14 blank | 9 comment | 43 complexity | ab2a017ba7b8872e4a7de65d2d54bc7e MD5 | raw file
- <?php
- class PodioObject
- {
- private $__attributes = array();
- private $__belongs_to;
- private $__properties = array();
- private $__relationships = array();
- protected $__id_column;
- public function init($default_attributes = array())
- {
- if (is_int($default_attributes)) {
- $default_attributes = array('id' => $default_attributes);
- }
- if (is_string($default_attributes)) {
- $default_attributes = array('external_id' => $default_attributes);
- }
- if (!is_array($default_attributes)) {
- $default_attributes = array();
- }
- $has_api_values = !empty($default_attributes['__api_values']);
- // Create object instance from attributes
- foreach ($this->__properties as $name => $property) {
- if (isset($property['options']['id'])) {
- $this->__id_column = $name;
- if (array_key_exists('id', $default_attributes)) {
- $this->id = $default_attributes['id'];
- }
- }
- if (array_key_exists($name, $default_attributes)) {
- // Special handling for PodioItemField values property so
- // we can construct using both the API format when receiving responses
- // and the much simpler podio-php format when constructing manually.
- if ($name == 'values' && !$has_api_values) {
- $this->values = $default_attributes[$name];
- } else {
- $this->set_attribute($name, $default_attributes[$name]);
- }
- }
- }
- if ($this->__relationships) {
- foreach ($this->__relationships as $name => $type) {
- if (array_key_exists($name, $default_attributes)) {
- $property = $this->__properties[$name];
- $class_name = 'Podio'.$property['type'];
- if ($type == 'has_one') {
- $child = is_object($default_attributes[$name]) ? $default_attributes[$name] : new $class_name($default_attributes[$name]);
- $child->add_relationship($this, $name);
- $this->set_attribute($name, $child);
- } elseif ($type == 'has_many' && is_array($default_attributes[$name])) {
- // Special handling for ItemField and AppField.
- // We need to create collection of the right type
- if ($class_name == 'PodioItemField') {
- $collection_class = 'PodioItemFieldCollection';
- $values = $default_attributes[$name];
- // Make sure we pass along info on whether the values property
- // contains API style values or not
- $collection = new $collection_class($values, $has_api_values);
- } elseif ($class_name == 'PodioAppField') {
- $collection_class = 'PodioAppFieldCollection';
- $values = $default_attributes[$name];
- $collection = new $collection_class($values);
- } else {
- $collection_class = 'PodioCollection';
- $values = array();
- foreach ($default_attributes[$name] as $value) {
- $child = is_object($value) ? $value : new $class_name($value);
- $values[] = $child;
- }
- $collection = new $collection_class($values);
- }
- $collection->add_relationship($this, $name);
- $this->set_attribute($name, $collection);
- }
- }
- }
- }
- }
- public function __set($name, $value)
- {
- if ($name == 'id' && !empty($this->__id_column)) {
- return $this->set_attribute($this->__id_column, $value);
- }
- return $this->set_attribute($name, $value);
- }
- public function __get($name)
- {
- if ($name == 'id' && !empty($this->__id_column)) {
- return empty($this->__attributes[$this->__id_column]) ? null : $this->__attributes[$this->__id_column];
- }
- if ($this->has_attribute($name)) {
- // Create DateTime object if necessary
- if ($this->has_property($name) && ($this->__properties[$name]['type'] == 'datetime' || $this->__properties[$name]['type'] == 'date')) {
- $tz = new DateTimeZone('UTC');
- return DateTime::createFromFormat($this->date_format_for_property($name), $this->__attributes[$name], $tz);
- }
- return $this->__attributes[$name];
- }
- }
- public function __isset($name)
- {
- return isset($this->__attributes[$name]);
- }
- public function __unset($name)
- {
- unset($this->__attributes[$name]);
- }
- public function __toString()
- {
- return print_r($this->as_json(false), true);
- }
- public function date_format_for_property($name)
- {
- if ($this->has_property($name)) {
- if ($this->__properties[$name]['type'] == 'datetime') {
- return 'Y-m-d H:i:s';
- } elseif ($this->__properties[$name]['type'] == 'date') {
- return 'Y-m-d';
- }
- }
- }
- public function relationship()
- {
- return $this->__belongs_to;
- }
- public function add_relationship($instance, $property = 'fields')
- {
- $this->__belongs_to = array('property' => $property, 'instance' => $instance);
- }
- protected function set_attribute($name, $value)
- {
- if ($this->has_property($name)) {
- $property = $this->__properties[$name];
- switch ($property['type']) {
- case 'integer':
- $this->__attributes[$name] = $value ? (int)$value : null;
- break;
- case 'boolean':
- $this->__attributes[$name] = null;
- if ($value === true || $value === false) {
- $this->__attributes[$name] = $value;
- } elseif ($value) {
- $this->__attributes[$name] = in_array(trim(strtolower($value)), array('true', 1, 'yes'));
- }
- break;
- case 'datetime':
- case 'date':
- if (is_a($value, 'DateTime')) {
- $this->__attributes[$name] = $value->format($this->date_format_for_property($name));
- } else {
- $this->__attributes[$name] = $value;
- }
- break;
- case 'string':
- if (is_array($value)) {
- $value = join(', ', $value);
- }
- $this->__attributes[$name] = $value ? (string)$value : null;
- break;
- case 'array':
- case 'hash':
- $this->__attributes[$name] = $value ? (array)$value : array();
- break;
- default:
- $this->__attributes[$name] = $value;
- }
- return true;
- }
- throw new PodioDataIntegrityError("Attribute cannot be assigned. Property '{$name}' doesn't exist.");
- }
- public static function listing($response_or_attributes)
- {
- if ($response_or_attributes) {
- if (is_object($response_or_attributes) && get_class($response_or_attributes) == 'PodioResponse') {
- $body = $response_or_attributes->json_body();
- } else {
- $body = $response_or_attributes;
- }
- $list = array();
- foreach ($body as $attributes) {
- $class_name = get_called_class();
- $list[] = new $class_name(array_merge($attributes, array('__api_values' => true)));
- }
- return $list;
- }
- }
- public static function member($response)
- {
- if ($response) {
- $class_name = get_called_class();
- return new $class_name(array_merge($response instanceof PodioResponse ? $response->json_body() : $response, array('__api_values' => true)));
- }
- }
- public static function collection($response, $collection_type = "PodioCollection")
- {
- if ($response) {
- $body = $response->json_body();
- $list = array();
- if (isset($body['items'])) {
- foreach ($body['items'] as $attributes) {
- $class_name = get_called_class();
- $list[] = new $class_name(array_merge($attributes, array('__api_values' => true)));
- }
- }
- return new $collection_type($list, $body['filtered'], $body['total']);
- }
- }
- public function can($right)
- {
- if ($this->has_property('rights')) {
- return $this->has_attribute('rights') && in_array($right, $this->rights);
- }
- return false;
- }
- public function has_attribute($name)
- {
- return array_key_exists($name, $this->__attributes);
- }
- public function has_property($name)
- {
- return array_key_exists($name, $this->__properties);
- }
- public function has_relationship($name)
- {
- return array_key_exists($name, $this->__relationships);
- }
- public function properties()
- {
- return $this->__properties;
- }
- public function relationships()
- {
- return $this->__relationships;
- }
- /**
- * Raw access to attributes. Only used for unit testing. Do not use.
- */
- public function __attribute($name)
- {
- return $this->__attributes[$name];
- }
- // Define a property on this object
- public function property($name, $type, $options = array())
- {
- if (!$this->has_property($name)) {
- $this->__properties[$name] = array('type' => $type, 'options' => $options);
- }
- }
- public function has_one($name, $class_name, $options = array())
- {
- $this->property($name, $class_name, $options);
- if (!$this->has_relationship($name)) {
- $this->__relationships[$name] = 'has_one';
- }
- }
- public function has_many($name, $class_name, $options = array())
- {
- $this->property($name, $class_name, $options);
- if (!$this->has_relationship($name)) {
- $this->__relationships[$name] = 'has_many';
- }
- }
- public function as_json($encoded = true)
- {
- $result = array();
- foreach ($this->__properties as $name => $property) {
- if (!$this->has_relationship($name) && $this->has_attribute($name) && !is_null($this->__attributes[$name])) {
- $result[$name] = $this->__attributes[$name];
- }
- }
- foreach ($this->__relationships as $name => $type) {
- if ($type == 'has_one') {
- $target_name = $name;
- if (!empty($this->__properties[$name]['options']['json_target'])) {
- $target_name = $this->__properties[$name]['options']['json_target'];
- }
- if ($this->has_attribute($name)) {
- if (!empty($this->__properties[$name]['options']['json_value'])) {
- $result[$target_name] = $this->__attributes[$name]->{$this->__properties[$name]['options']['json_value']};
- } elseif (is_a($this->__attributes[$name], 'PodioFieldCollection')) {
- foreach ($this->__attributes[$name] as $field) {
- // Only use external_id for item fields
- $key = $field->external_id && is_a($this->__attributes[$name], 'PodioItemFieldCollection') ? $field->external_id : $field->id;
- $list[$key] = $field->as_json(false);
- }
- $result[$name] = $list;
- } elseif (is_object($this->__attributes[$name]) && get_class($this->__attributes[$name]) == 'PodioReference') {
- $result['ref_type'] = $this->__attributes[$name]->type;
- $result['ref_id'] = $this->__attributes[$name]->id;
- } else {
- $child = $this->__attributes[$name]->as_json(false);
- if ($child) {
- $result[$target_name] = $child;
- }
- }
- }
- } elseif ($type == 'has_many') {
- if ($this->has_attribute($name)) {
- $list = array();
- foreach ($this->__attributes[$name] as $item) {
- if (!empty($this->__properties[$name]['options']['json_value'])) {
- $list[] = $item->{$this->__properties[$name]['options']['json_value']};
- }
- // TODO: This really should be moved to PodioCollection (should implement as_json)
- // and PodioItemFieldCollection for the special case
- elseif (get_class($this->__attributes[$name]) === 'PodioItemFieldCollection') {
- $key = $item->external_id ? $item->external_id : (string)$item->field_id;
- $list[$key] = $item->as_json(false);
- } else {
- $list[] = $item->as_json(false);
- }
- }
- if ($list) {
- if (!empty($this->__properties[$name]['options']['json_target'])) {
- $result[$this->__properties[$name]['options']['json_target']] = $list;
- } else {
- $result[$name] = $list;
- }
- }
- }
- }
- }
- if ($result) {
- return $encoded ? json_encode($result) : $result;
- }
- return null;
- }
- }