ACC SHELL
<?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
{
/**
* 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);
}
}
ACC SHELL 2018