PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/backwpup/vendor/rackspace/php-opencloud/lib/OpenCloud/Common/Base.php

https://bitbucket.org/ed47/epfl-smart-move
PHP | 437 lines | 235 code | 49 blank | 153 comment | 34 complexity | 43f71d2174ef6d042739d91f3eecbd55 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Copyright 2012-2014 Rackspace US, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace OpenCloud\Common;
  18. use OpenCloud\Common\Collection\ResourceIterator;
  19. use OpenCloud\Common\Constants\Header as HeaderConst;
  20. use OpenCloud\Common\Constants\Mime as MimeConst;
  21. use OpenCloud\Common\Exceptions\JsonError;
  22. use Psr\Log\LoggerInterface;
  23. /**
  24. * The root class for all other objects used or defined by this SDK.
  25. *
  26. * It contains common code for error handling as well as service functions that
  27. * are useful. Because it is an abstract class, it cannot be called directly,
  28. * and it has no publicly-visible properties.
  29. */
  30. abstract class Base
  31. {
  32. const PATCH_CONTENT_TYPE = MimeConst::JSON_PATCH;
  33. /**
  34. * Holds all the properties added by overloading.
  35. *
  36. * @var array
  37. */
  38. private $properties = array();
  39. /**
  40. * The logger instance
  41. *
  42. * @var LoggerInterface
  43. */
  44. private $logger;
  45. /**
  46. * The aliases configure for the properties of the instance.
  47. *
  48. * @var array
  49. */
  50. protected $aliases = array();
  51. /**
  52. * @return static
  53. */
  54. public static function getInstance()
  55. {
  56. return new static();
  57. }
  58. /**
  59. * Intercept non-existent method calls for dynamic getter/setter functionality.
  60. *
  61. * @param $method
  62. * @param $args
  63. * @throws Exceptions\RuntimeException
  64. */
  65. public function __call($method, $args)
  66. {
  67. $prefix = substr($method, 0, 3);
  68. // Get property - convert from camel case to underscore
  69. $property = lcfirst(substr($method, 3));
  70. // Only do these methods on properties which exist
  71. if ($this->propertyExists($property) && $prefix == 'get') {
  72. return $this->getProperty($property);
  73. }
  74. // Do setter
  75. if ($this->propertyExists($property) && $prefix == 'set') {
  76. return $this->setProperty($property, $args[0]);
  77. }
  78. throw new Exceptions\RuntimeException(sprintf(
  79. 'No method %s::%s()',
  80. get_class($this),
  81. $method
  82. ));
  83. }
  84. /**
  85. * We can set a property under three conditions:
  86. *
  87. * 1. If it has a concrete setter: setProperty()
  88. * 2. If the property exists
  89. * 3. If the property name's prefix is in an approved list
  90. *
  91. * @param mixed $property
  92. * @param mixed $value
  93. * @return mixed
  94. */
  95. protected function setProperty($property, $value)
  96. {
  97. $setter = 'set' . $this->toCamel($property);
  98. if (method_exists($this, $setter)) {
  99. return call_user_func(array($this, $setter), $value);
  100. } elseif (false !== ($propertyVal = $this->propertyExists($property))) {
  101. // Are we setting a public or private property?
  102. if ($this->isAccessible($propertyVal)) {
  103. $this->$propertyVal = $value;
  104. } else {
  105. $this->properties[$propertyVal] = $value;
  106. }
  107. return $this;
  108. } else {
  109. $this->getLogger()->warning(
  110. 'Attempted to set {property} with value {value}, but the'
  111. . ' property has not been defined. Please define first.',
  112. array(
  113. 'property' => $property,
  114. 'value' => print_r($value, true)
  115. )
  116. );
  117. }
  118. }
  119. /**
  120. * Basic check to see whether property exists.
  121. *
  122. * @param string $property The property name being investigated.
  123. * @param bool $allowRetry If set to TRUE, the check will try to format the name in underscores because
  124. * there are sometimes discrepancies between camelCaseNames and underscore_names.
  125. * @return bool
  126. */
  127. protected function propertyExists($property, $allowRetry = true)
  128. {
  129. if (!property_exists($this, $property) && !$this->checkAttributePrefix($property)) {
  130. // Convert to under_score and retry
  131. if ($allowRetry) {
  132. return $this->propertyExists($this->toUnderscores($property), false);
  133. } else {
  134. $property = false;
  135. }
  136. }
  137. return $property;
  138. }
  139. /**
  140. * Convert a string to camelCase format.
  141. *
  142. * @param $string
  143. * @param bool $capitalise Optional flag which allows for word capitalization.
  144. * @return mixed
  145. */
  146. public function toCamel($string, $capitalise = true)
  147. {
  148. if ($capitalise) {
  149. $string = ucfirst($string);
  150. }
  151. return preg_replace_callback('/_([a-z])/', function ($char) {
  152. return strtoupper($char[1]);
  153. }, $string);
  154. }
  155. /**
  156. * Convert string to underscore format.
  157. *
  158. * @param $string
  159. * @return mixed
  160. */
  161. public function toUnderscores($string)
  162. {
  163. $string = lcfirst($string);
  164. return preg_replace_callback('/([A-Z])/', function ($char) {
  165. return "_" . strtolower($char[1]);
  166. }, $string);
  167. }
  168. /**
  169. * Does the property exist in the object variable list (i.e. does it have public or protected visibility?)
  170. *
  171. * @param $property
  172. * @return bool
  173. */
  174. private function isAccessible($property)
  175. {
  176. return array_key_exists($property, get_object_vars($this));
  177. }
  178. /**
  179. * Checks the attribute $property and only permits it if the prefix is
  180. * in the specified $prefixes array
  181. *
  182. * This is to support extension namespaces in some services.
  183. *
  184. * @param string $property the name of the attribute
  185. * @return boolean
  186. */
  187. private function checkAttributePrefix($property)
  188. {
  189. if (!method_exists($this, 'getService')) {
  190. return false;
  191. }
  192. $prefix = strstr($property, ':', true);
  193. return in_array($prefix, $this->getService()->namespaces());
  194. }
  195. /**
  196. * Grab value out of the data array.
  197. *
  198. * @param string $property
  199. * @return mixed
  200. */
  201. protected function getProperty($property)
  202. {
  203. if (array_key_exists($property, $this->properties)) {
  204. return $this->properties[$property];
  205. } elseif (array_key_exists($this->toUnderscores($property), $this->properties)) {
  206. return $this->properties[$this->toUnderscores($property)];
  207. } elseif (method_exists($this, 'get' . ucfirst($property))) {
  208. return call_user_func(array($this, 'get' . ucfirst($property)));
  209. } elseif (false !== ($propertyVal = $this->propertyExists($property)) && $this->isAccessible($propertyVal)) {
  210. return $this->$propertyVal;
  211. }
  212. return null;
  213. }
  214. /**
  215. * Sets the logger.
  216. *
  217. * @param LoggerInterface $logger
  218. *
  219. * @return $this
  220. */
  221. public function setLogger(LoggerInterface $logger = null)
  222. {
  223. $this->logger = $logger;
  224. return $this;
  225. }
  226. /**
  227. * Returns the Logger object.
  228. *
  229. * @return LoggerInterface
  230. */
  231. public function getLogger()
  232. {
  233. if (null === $this->logger) {
  234. $this->setLogger(new Log\Logger);
  235. }
  236. return $this->logger;
  237. }
  238. /**
  239. * @return bool
  240. */
  241. public function hasLogger()
  242. {
  243. return (null !== $this->logger);
  244. }
  245. /**
  246. * @deprecated
  247. */
  248. public function url($path = null, array $query = array())
  249. {
  250. return $this->getUrl($path, $query);
  251. }
  252. /**
  253. * Populates the current object based on an unknown data type.
  254. *
  255. * @param mixed $info
  256. * @param bool
  257. * @throws Exceptions\InvalidArgumentError
  258. */
  259. public function populate($info, $setObjects = true)
  260. {
  261. if (is_string($info) || is_integer($info)) {
  262. $this->setProperty($this->primaryKeyField(), $info);
  263. $this->refresh($info);
  264. } elseif (is_object($info) || is_array($info)) {
  265. foreach ($info as $key => $value) {
  266. if ($key == 'metadata' || $key == 'meta') {
  267. // Try retrieving existing value
  268. if (null === ($metadata = $this->getProperty($key))) {
  269. // If none exists, create new object
  270. $metadata = new Metadata;
  271. }
  272. // Set values for metadata
  273. $metadata->setArray($value);
  274. // Set object property
  275. $this->setProperty($key, $metadata);
  276. } elseif (!empty($this->associatedResources[$key]) && $setObjects === true) {
  277. // Associated resource
  278. try {
  279. $resource = $this->getService()->resource($this->associatedResources[$key], $value);
  280. $resource->setParent($this);
  281. $this->setProperty($key, $resource);
  282. } catch (Exception\ServiceException $e) {
  283. }
  284. } elseif (!empty($this->associatedCollections[$key]) && $setObjects === true) {
  285. // Associated collection
  286. try {
  287. $className = $this->associatedCollections[$key];
  288. $options = $this->makeResourceIteratorOptions($className);
  289. $iterator = ResourceIterator::factory($this, $options, $value);
  290. $this->setProperty($key, $iterator);
  291. } catch (Exception\ServiceException $e) {
  292. }
  293. } elseif (!empty($this->aliases[$key])) {
  294. // Sometimes we might want to preserve camelCase
  295. // or covert `rax-bandwidth:bandwidth` to `raxBandwidth`
  296. $this->setProperty($this->aliases[$key], $value);
  297. } else {
  298. // Normal key/value pair
  299. $this->setProperty($key, $value);
  300. }
  301. }
  302. } elseif (null !== $info) {
  303. throw new Exceptions\InvalidArgumentError(sprintf(
  304. Lang::translate('Argument for [%s] must be string or object'),
  305. get_class()
  306. ));
  307. }
  308. }
  309. /**
  310. * Checks the most recent JSON operation for errors.
  311. *
  312. * @throws Exceptions\JsonError
  313. * @codeCoverageIgnore
  314. */
  315. public static function checkJsonError()
  316. {
  317. switch (json_last_error()) {
  318. case JSON_ERROR_NONE:
  319. return;
  320. case JSON_ERROR_DEPTH:
  321. $jsonError = 'JSON error: The maximum stack depth has been exceeded';
  322. break;
  323. case JSON_ERROR_STATE_MISMATCH:
  324. $jsonError = 'JSON error: Invalid or malformed JSON';
  325. break;
  326. case JSON_ERROR_CTRL_CHAR:
  327. $jsonError = 'JSON error: Control character error, possibly incorrectly encoded';
  328. break;
  329. case JSON_ERROR_SYNTAX:
  330. $jsonError = 'JSON error: Syntax error';
  331. break;
  332. case JSON_ERROR_UTF8:
  333. $jsonError = 'JSON error: Malformed UTF-8 characters, possibly incorrectly encoded';
  334. break;
  335. default:
  336. $jsonError = 'Unexpected JSON error';
  337. break;
  338. }
  339. if (isset($jsonError)) {
  340. throw new JsonError(Lang::translate($jsonError));
  341. }
  342. }
  343. public static function generateUuid()
  344. {
  345. return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
  346. // 32 bits for "time_low"
  347. mt_rand(0, 0xffff), mt_rand(0, 0xffff),
  348. // 16 bits for "time_mid"
  349. mt_rand(0, 0xffff),
  350. // 16 bits for "time_hi_and_version",
  351. // four most significant bits holds version number 4
  352. mt_rand(0, 0x0fff) | 0x4000,
  353. // 16 bits, 8 bits for "clk_seq_hi_res",
  354. // 8 bits for "clk_seq_low",
  355. // two most significant bits holds zero and one for variant DCE1.1
  356. mt_rand(0, 0x3fff) | 0x8000,
  357. // 48 bits for "node"
  358. mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
  359. );
  360. }
  361. public function makeResourceIteratorOptions($resource)
  362. {
  363. $options = array('resourceClass' => $this->stripNamespace($resource));
  364. if (method_exists($resource, 'jsonCollectionName')) {
  365. $options['key.collection'] = $resource::jsonCollectionName();
  366. }
  367. if (method_exists($resource, 'jsonCollectionElement')) {
  368. $options['key.collectionElement'] = $resource::jsonCollectionElement();
  369. }
  370. return $options;
  371. }
  372. public function stripNamespace($namespace)
  373. {
  374. $array = explode('\\', $namespace);
  375. return end($array);
  376. }
  377. protected static function getJsonHeader()
  378. {
  379. return array(HeaderConst::CONTENT_TYPE => MimeConst::JSON);
  380. }
  381. protected static function getPatchHeaders()
  382. {
  383. return array(HeaderConst::CONTENT_TYPE => static::PATCH_CONTENT_TYPE);
  384. }
  385. }