?iť?
Current Path : /home/scgforma/www/cloud/3rdparty/rackspace/php-opencloud/lib/OpenCloud/Common/ |
Current File : /home/scgforma/www/cloud/3rdparty/rackspace/php-opencloud/lib/OpenCloud/Common/Base.php |
<?php /** * Copyright 2012-2014 Rackspace US, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace OpenCloud\Common; use OpenCloud\Common\Collection\ResourceIterator; use OpenCloud\Common\Constants\Header as HeaderConst; use OpenCloud\Common\Constants\Mime as MimeConst; use OpenCloud\Common\Exceptions\JsonError; use Psr\Log\LoggerInterface; /** * The root class for all other objects used or defined by this SDK. * * It contains common code for error handling as well as service functions that * are useful. Because it is an abstract class, it cannot be called directly, * and it has no publicly-visible properties. */ abstract class Base { const PATCH_CONTENT_TYPE = MimeConst::JSON_PATCH; /** * Holds all the properties added by overloading. * * @var array */ private $properties = array(); /** * The logger instance * * @var LoggerInterface */ private $logger; /** * The aliases configure for the properties of the instance. * * @var array */ protected $aliases = array(); /** * @return static */ public static function getInstance() { return new static(); } /** * Intercept non-existent method calls for dynamic getter/setter functionality. * * @param $method * @param $args * @throws Exceptions\RuntimeException */ public function __call($method, $args) { $prefix = substr($method, 0, 3); // Get property - convert from camel case to underscore $property = lcfirst(substr($method, 3)); // Only do these methods on properties which exist if ($this->propertyExists($property) && $prefix == 'get') { return $this->getProperty($property); } // Do setter if ($this->propertyExists($property) && $prefix == 'set') { return $this->setProperty($property, $args[0]); } throw new Exceptions\RuntimeException(sprintf( 'No method %s::%s()', get_class($this), $method )); } /** * We can set a property under three conditions: * * 1. If it has a concrete setter: setProperty() * 2. If the property exists * 3. If the property name's prefix is in an approved list * * @param mixed $property * @param mixed $value * @return mixed */ protected function setProperty($property, $value) { $setter = 'set' . $this->toCamel($property); if (method_exists($this, $setter)) { return call_user_func(array($this, $setter), $value); } elseif (false !== ($propertyVal = $this->propertyExists($property))) { // Are we setting a public or private property? if ($this->isAccessible($propertyVal)) { $this->$propertyVal = $value; } else { $this->properties[$propertyVal] = $value; } return $this; } else { $this->getLogger()->warning( 'Attempted to set {property} with value {value}, but the' . ' property has not been defined. Please define first.', array( 'property' => $property, 'value' => print_r($value, true) ) ); } } /** * Basic check to see whether property exists. * * @param string $property The property name being investigated. * @param bool $allowRetry If set to TRUE, the check will try to format the name in underscores because * there are sometimes discrepancies between camelCaseNames and underscore_names. * @return bool */ protected function propertyExists($property, $allowRetry = true) { if (!property_exists($this, $property) && !$this->checkAttributePrefix($property)) { // Convert to under_score and retry if ($allowRetry) { return $this->propertyExists($this->toUnderscores($property), false); } else { $property = false; } } return $property; } /** * Convert a string to camelCase format. * * @param $string * @param bool $capitalise Optional flag which allows for word capitalization. * @return mixed */ public function toCamel($string, $capitalise = true) { if ($capitalise) { $string = ucfirst($string); } return preg_replace_callback('/_([a-z])/', function ($char) { return strtoupper($char[1]); }, $string); } /** * Convert string to underscore format. * * @param $string * @return mixed */ public function toUnderscores($string) { $string = lcfirst($string); return preg_replace_callback('/([A-Z])/', function ($char) { return "_" . strtolower($char[1]); }, $string); } /** * Does the property exist in the object variable list (i.e. does it have public or protected visibility?) * * @param $property * @return bool */ private function isAccessible($property) { return array_key_exists($property, get_object_vars($this)); } /** * Checks the attribute $property and only permits it if the prefix is * in the specified $prefixes array * * This is to support extension namespaces in some services. * * @param string $property the name of the attribute * @return boolean */ private function checkAttributePrefix($property) { if (!method_exists($this, 'getService')) { return false; } $prefix = strstr($property, ':', true); return in_array($prefix, $this->getService()->namespaces()); } /** * Grab value out of the data array. * * @param string $property * @return mixed */ protected function getProperty($property) { if (array_key_exists($property, $this->properties)) { return $this->properties[$property]; } elseif (array_key_exists($this->toUnderscores($property), $this->properties)) { return $this->properties[$this->toUnderscores($property)]; } elseif (method_exists($this, 'get' . ucfirst($property))) { return call_user_func(array($this, 'get' . ucfirst($property))); } elseif (false !== ($propertyVal = $this->propertyExists($property)) && $this->isAccessible($propertyVal)) { return $this->$propertyVal; } return null; } /** * Sets the logger. * * @param LoggerInterface $logger * * @return $this */ public function setLogger(LoggerInterface $logger = null) { $this->logger = $logger; return $this; } /** * Returns the Logger object. * * @return LoggerInterface */ public function getLogger() { if (null === $this->logger) { $this->setLogger(new Log\Logger); } return $this->logger; } /** * @return bool */ public function hasLogger() { return (null !== $this->logger); } /** * @deprecated */ public function url($path = null, array $query = array()) { return $this->getUrl($path, $query); } /** * Populates the current object based on an unknown data type. * * @param mixed $info * @param bool * @throws Exceptions\InvalidArgumentError */ public function populate($info, $setObjects = true) { if (is_string($info) || is_integer($info)) { $this->setProperty($this->primaryKeyField(), $info); $this->refresh($info); } elseif (is_object($info) || is_array($info)) { foreach ($info as $key => $value) { if ($key == 'metadata' || $key == 'meta') { // Try retrieving existing value if (null === ($metadata = $this->getProperty($key))) { // If none exists, create new object $metadata = new Metadata; } // Set values for metadata $metadata->setArray($value); // Set object property $this->setProperty($key, $metadata); } elseif (!empty($this->associatedResources[$key]) && $setObjects === true) { // Associated resource try { $resource = $this->getService()->resource($this->associatedResources[$key], $value); $resource->setParent($this); $this->setProperty($key, $resource); } catch (Exception\ServiceException $e) { } } elseif (!empty($this->associatedCollections[$key]) && $setObjects === true) { // Associated collection try { $className = $this->associatedCollections[$key]; $options = $this->makeResourceIteratorOptions($className); $iterator = ResourceIterator::factory($this, $options, $value); $this->setProperty($key, $iterator); } catch (Exception\ServiceException $e) { } } elseif (!empty($this->aliases[$key])) { // Sometimes we might want to preserve camelCase // or covert `rax-bandwidth:bandwidth` to `raxBandwidth` $this->setProperty($this->aliases[$key], $value); } else { // Normal key/value pair $this->setProperty($key, $value); } } } elseif (null !== $info) { throw new Exceptions\InvalidArgumentError(sprintf( Lang::translate('Argument for [%s] must be string or object'), get_class() )); } } /** * Checks the most recent JSON operation for errors. * * @throws Exceptions\JsonError * @codeCoverageIgnore */ public static function checkJsonError() { switch (json_last_error()) { case JSON_ERROR_NONE: return; case JSON_ERROR_DEPTH: $jsonError = 'JSON error: The maximum stack depth has been exceeded'; break; case JSON_ERROR_STATE_MISMATCH: $jsonError = 'JSON error: Invalid or malformed JSON'; break; case JSON_ERROR_CTRL_CHAR: $jsonError = 'JSON error: Control character error, possibly incorrectly encoded'; break; case JSON_ERROR_SYNTAX: $jsonError = 'JSON error: Syntax error'; break; case JSON_ERROR_UTF8: $jsonError = 'JSON error: Malformed UTF-8 characters, possibly incorrectly encoded'; break; default: $jsonError = 'Unexpected JSON error'; break; } if (isset($jsonError)) { throw new JsonError(Lang::translate($jsonError)); } } public static function generateUuid() { return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', // 32 bits for "time_low" mt_rand(0, 0xffff), mt_rand(0, 0xffff), // 16 bits for "time_mid" mt_rand(0, 0xffff), // 16 bits for "time_hi_and_version", // four most significant bits holds version number 4 mt_rand(0, 0x0fff) | 0x4000, // 16 bits, 8 bits for "clk_seq_hi_res", // 8 bits for "clk_seq_low", // two most significant bits holds zero and one for variant DCE1.1 mt_rand(0, 0x3fff) | 0x8000, // 48 bits for "node" mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } public function makeResourceIteratorOptions($resource) { $options = array('resourceClass' => $this->stripNamespace($resource)); if (method_exists($resource, 'jsonCollectionName')) { $options['key.collection'] = $resource::jsonCollectionName(); } if (method_exists($resource, 'jsonCollectionElement')) { $options['key.collectionElement'] = $resource::jsonCollectionElement(); } return $options; } public function stripNamespace($namespace) { $array = explode('\\', $namespace); return end($array); } protected static function getJsonHeader() { return array(HeaderConst::CONTENT_TYPE => MimeConst::JSON); } protected static function getPatchHeaders() { return array(HeaderConst::CONTENT_TYPE => static::PATCH_CONTENT_TYPE); } }