Example #1
0
 /**
  * Get the class name for the Model. Purely based on the name property.
  *
  * @param bool $with_ns
  * @return mixed
  */
 public function getClassName($with_ns = false)
 {
     $class_name = Helpers::singularize($this->getName());
     if ($with_ns) {
         return sprintf('%s\\%s', $this->getNamespace(), $class_name);
     } else {
         return $class_name;
     }
 }
Example #2
0
 public function send()
 {
     //Sign the request - this just sets the Authorization header
     $this->app->getOAuthClient()->sign($this);
     // configure curl
     $ch = curl_init();
     curl_setopt_array($ch, $this->app->getConfig('curl'));
     curl_setopt($ch, CURLINFO_HEADER_OUT, true);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->getMethod());
     if (isset($this->body)) {
         curl_setopt($ch, CURLOPT_POSTFIELDS, $this->body);
     }
     //build header array.  Don't provide glue so it'll return the array itself.
     //Maybe could be a but cleaner but nice to reuse code.
     $header_array = Helpers::flattenAssocArray($this->getHeaders(), '%s: %s');
     curl_setopt($ch, CURLOPT_HTTPHEADER, $header_array);
     $full_uri = $this->getUrl()->getFullURL();
     //build parameter array - the only time there's a post body is with the XML,
     //only escape at this point
     $query_string = Helpers::flattenAssocArray($this->getParameters(), '%s=%s', '&', true);
     if (strlen($query_string) > 0) {
         $full_uri .= "?{$query_string}";
     }
     curl_setopt($ch, CURLOPT_URL, $full_uri);
     if ($this->method === self::METHOD_POST || $this->method === self::METHOD_PUT) {
         curl_setopt($ch, CURLOPT_POST, true);
     }
     $response = curl_exec($ch);
     $info = curl_getinfo($ch);
     if ($response === false) {
         throw new Exception('Curl error: ' . curl_error($ch));
     }
     $this->response = new Response($this, $response, $info);
     $this->response->parse();
     return $this->response;
 }
Example #3
0
 /**
  * Function to save properties directly which do not update via a POST
  *
  * This is called automatically from the save method for things like adding contacts to ContactGroups
  *
  * @param Object $object
  * @throws Exception
  */
 private function savePropertiesDirectly(Object $object)
 {
     foreach ($object::getProperties() as $property_name => $meta) {
         if ($meta[Object::KEY_SAVE_DIRECTLY] && $object->isPropertyDirty($property_name)) {
             //Then actually save
             $property_objects = $object->{$property_name};
             $property_type = get_class(current($property_objects));
             $url = new URL($this, sprintf('%s/%s/%s', $object::getResourceURI(), $object->getGUID(), $property_type::getResourceURI()));
             $request = new Request($this, $url, Request::METHOD_PUT);
             $property_array = array();
             foreach ($property_objects as $property_object) {
                 $property_array[] = $property_object->toStringArray();
             }
             $root_node_name = Helpers::pluralize($property_type::getRootNodeName());
             $request->setBody(Helpers::arrayToXML(array($root_node_name => $property_array)));
             $request->send();
             $response = $request->getResponse();
             foreach ($response->getElements() as $element_index => $element) {
                 if ($response->getErrorsForElement($element_index) === null) {
                     $property_objects[$element_index]->fromStringArray($element);
                     $property_objects[$element_index]->setClean();
                 }
             }
             //Set it clean so the following save might have nothing to do.
             $object->setClean($property_name);
         }
     }
 }
Example #4
0
 public function parseXML()
 {
     $sxml = new SimpleXMLElement($this->response_body);
     // For lack of a better way to find the elements returned (every time)
     // XML has an array 2 levels deep due to its non-unique key nature.
     /** @var SimpleXMLElement $root_child */
     foreach ($sxml as $child_index => $root_child) {
         switch ($child_index) {
             case 'ErrorNumber':
                 $this->root_error['code'] = (string) $root_child;
                 break;
             case 'Type':
                 $this->root_error['type'] = (string) $root_child;
                 break;
             case 'Message':
                 $this->root_error['message'] = (string) $root_child;
                 break;
             case 'Payslip':
             case 'PayItems':
                 // some xero endpoints are 1D so we can parse them straight away
                 $this->elements[] = Helpers::XMLToArray($root_child);
                 break;
             default:
                 //Happy to make the assumption that there will only be one
                 //root node with > than 2D children.
                 foreach ($root_child->children() as $element_index => $element) {
                     $this->elements[] = Helpers::XMLToArray($element);
                 }
         }
     }
 }
Example #5
0
 /**
  * @return string
  */
 public function getNameSingular()
 {
     return \XeroPHP\Helpers::singularize($this->getName());
 }
Example #6
0
 /**
  * Get the Signature Base String for signing.  This is basically just all params (including the generated oauth ones)
  * ordered by key, then concatenated with the method and URL
  * GET&https%3A%2F%2Fapi.xero.com%2Fapi.xro%2F2.0%2FContacts&oauth_consumer etc.
  *
  * @return string
  */
 public function getSBS()
 {
     $oauth_params = $this->getOAuthParams();
     $request_params = $this->request->getParameters();
     $sbs_params = array_merge($request_params, $oauth_params);
     //Params need sorting so signing order is the same
     ksort($sbs_params);
     $sbs_string = Helpers::flattenAssocArray($sbs_params, '%s=%s', '&', true);
     $url = $this->request->getUrl()->getFullURL();
     //Every second thing seems to need escaping!
     return sprintf('%s&%s&%s', $this->request->getMethod(), Helpers::escape($url), Helpers::escape($sbs_string));
 }
Example #7
0
 /**
  * Search for an entity based on a term. Search by class name, FQ class name - both as-is, plural and singular
  *
  * Crude.
  *
  * @param $key
  * @param string $namespace_hint
  * @return null
  */
 public function searchByKey($key, $namespace_hint = '')
 {
     if (!$this->isIndexed()) {
         $this->buildSearchIndex();
     }
     //Yuck
     $plural_key = Helpers::pluralize($key);
     $singular_key = Helpers::singularize($key);
     $ns_key = sprintf('%s\\%s', $namespace_hint, $key);
     $plural_ns_key = Helpers::pluralize($ns_key);
     $singular_ns_key = Helpers::singularize($ns_key);
     if (isset($this->search_keys[$ns_key])) {
         return $this->search_keys[$ns_key];
     } elseif (isset($this->search_keys[$plural_ns_key])) {
         return $this->search_keys[$plural_ns_key];
     } elseif (isset($this->search_keys[$singular_ns_key])) {
         return $this->search_keys[$singular_ns_key];
     } elseif (isset($this->search_keys[$key])) {
         return $this->search_keys[$key];
     } elseif (isset($this->search_keys[$plural_key])) {
         return $this->search_keys[$plural_key];
     } elseif (isset($this->search_keys[$singular_key])) {
         return $this->search_keys[$singular_key];
     } else {
         return null;
     }
 }
Example #8
0
 /**
  * Load an assoc array into the instance of the object $property => $value
  * $replace_data - replace existing data
  *
  * @param $input_array
  * @param $replace_data
  */
 public function fromStringArray($input_array, $replace_data = false)
 {
     foreach (static::getProperties() as $property => $meta) {
         $type = $meta[self::KEY_TYPE];
         $php_type = $meta[self::KEY_PHP_TYPE];
         //If set and NOT replace data, continue
         if (!$replace_data && isset($this->_data[$property])) {
             continue;
         }
         if (!isset($input_array[$property])) {
             $this->_data[$property] = null;
             continue;
         }
         //Fix for an earlier assumption that the API didn't return more than
         //two levels of nested objects.
         //Handles Invoice > Contact > Address etc. in one build.
         if (is_array($input_array[$property]) && Helpers::isAssoc($input_array[$property]) === false) {
             $collection = new Collection();
             $collection->addAssociatedObject($property, $this);
             foreach ($input_array[$property] as $assoc_element) {
                 $cast = self::castFromString($type, $assoc_element, $php_type);
                 //Do this here so that you know it's not a static method call to ::castFromString
                 if ($cast instanceof Object) {
                     $cast->addAssociatedObject($property, $this);
                 }
                 $collection->append($cast);
             }
             $this->_data[$property] = $collection;
         } else {
             $cast = self::castFromString($type, $input_array[$property], $php_type);
             //Do this here so that you know it's not a static method call to ::castFromString
             if ($cast instanceof Object) {
                 $cast->addAssociatedObject($property, $this);
             }
             $this->_data[$property] = $cast;
         }
     }
 }
Example #9
0
 /**
  * Get the prefix for the constant name generation and strip out 'Types'
  * eg. XERO_USER_ROLE
  *
  * @return mixed
  */
 public function getConstantPrefix()
 {
     $sane_name = preg_replace('/\\([\\w\\s]+\\)/', '', $this->raw_name);
     return \XeroPHP\Helpers::singularize(preg_replace('/(\\b(code)s?)/i', '', trim($sane_name)));
 }