diff options
| author | root <root@kabir-PC> | 2016-03-23 11:31:51 +0100 |
|---|---|---|
| committer | root <root@kabir-PC> | 2016-03-23 11:31:51 +0100 |
| commit | a26989103d70fb0dd3ff6834de107cae246778c3 (patch) | |
| tree | 0f243c83b790ffb57f19261fc2a509131f6776ce /server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php | |
| parent | 1342db60283cb61a1c3810993575d35b9fb33ac0 (diff) | |
| parent | 6e78d76f887d1149ea85bfb06db7ee7ad7435f5a (diff) | |
Merge branch 'develop' of https://github.com/manzerbredes/istic-openstack into develop
Diffstat (limited to 'server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php')
| -rw-r--r-- | server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php b/server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php new file mode 100644 index 0000000..9f79b07 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php @@ -0,0 +1,243 @@ +<?php + +namespace OpenCloud\Common\Resource; + +use OpenCloud\Common\Api\Operator; +use OpenCloud\Common\Transport\Utils; +use Psr\Http\Message\ResponseInterface; + +/** + * Represents a top-level abstraction of a remote API resource. Usually a resource represents a discrete + * entity such as a Server, Container, Load Balancer. Apart from a representation of state, a resource can + * also execute RESTFul operations on itself (updating, deleting, listing) or on other models. + * + * @package OpenCloud\Common\Resource + */ +abstract class AbstractResource extends Operator implements ResourceInterface +{ + const DEFAULT_MARKER_KEY = 'id'; + + /** + * The JSON key that indicates how the API nests singular resources. For example, when + * performing a GET, it could respond with ``{"server": {"id": "12345"}}``. In this case, + * "server" is the resource key, since the essential state of the server is nested inside. + * + * @var string + */ + protected $resourceKey; + + /** + * The key that indicates how the API nests resource collections. For example, when + * performing a GET, it could respond with ``{"servers": [{}, {}]}``. In this case, "servers" + * is the resources key, since the array of servers is nested inside. + * + * @var string + */ + protected $resourcesKey; + + /** + * Indicates which attribute of the current resource should be used for pagination markers. + * + * @var string + */ + protected $markerKey; + + /** + * An array of aliases that will be checked when the resource is being populated. For example, + * + * 'FOO_BAR' => 'fooBar' + * + * will extract FOO_BAR from the response, and save it as 'fooBar' in the resource. + * + * @var array + */ + protected $aliases = []; + + /** + * Populates the current resource from a response object. + * + * @param ResponseInterface $response + * + * @return $this|ResourceInterface + */ + public function populateFromResponse(ResponseInterface $response) + { + if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) { + $json = Utils::jsonDecode($response); + if (!empty($json)) { + $this->populateFromArray(Utils::flattenJson($json, $this->resourceKey)); + } + } + + return $this; + } + + /** + * Populates the current resource from a data array. + * + * @param array $array + * + * @return mixed|void + */ + public function populateFromArray(array $array) + { + $reflClass = new \ReflectionClass($this); + + foreach ($array as $key => $val) { + $propertyName = isset($this->aliases[$key]) ? $this->aliases[$key] : $key; + + if (property_exists($this, $propertyName)) { + if ($type = $this->extractTypeFromDocBlock($reflClass, $propertyName)) { + $val = $this->parseDocBlockValue($type, $val); + } + + $this->$propertyName = $val; + } + } + } + + private function parseDocBlockValue($type, $val) + { + if (strpos($type, '[]') === 0 && is_array($val)) { + $array = []; + foreach ($val as $subVal) { + $array[] = $this->model($this->normalizeModelClass(substr($type, 2)), $subVal); + } + $val = $array; + } elseif (strcasecmp($type, '\datetimeimmutable') === 0) { + $val = new \DateTimeImmutable($val); + } elseif ($this->isNotNativeType($type)) { + $val = $this->model($this->normalizeModelClass($type), $val); + } + + return $val; + } + + private function isNotNativeType($type) + { + return !in_array($type, [ + 'string', 'bool', 'boolean', 'double', 'null', 'array', 'object', 'int', 'integer', 'float', 'numeric', + 'mixed' + ]); + } + + private function normalizeModelClass($class) + { + if (strpos($class, '\\') === false) { + $currentNamespace = (new \ReflectionClass($this))->getNamespaceName(); + $class = sprintf("%s\\%s", $currentNamespace, $class); + } + + return $class; + } + + private function extractTypeFromDocBlock(\ReflectionClass $reflClass, $propertyName) + { + $docComment = $reflClass->getProperty($propertyName)->getDocComment(); + + if (!$docComment) { + return false; + } + + $matches = []; + preg_match('#@var ((\[\])?[\w|\\\]+)#', $docComment, $matches); + return isset($matches[1]) ? $matches[1] : null; + } + + /** + * Internal method which retrieves the values of provided keys. + * + * @param array $keys + * + * @return array + */ + protected function getAttrs(array $keys) + { + $output = []; + + foreach ($keys as $key) { + if (property_exists($this, $key) && $this->$key !== null) { + $output[$key] = $this->$key; + } + } + + return $output; + } + + /** + * @param array $definition + * + * @return mixed + */ + public function executeWithState(array $definition) + { + return $this->execute($definition, $this->getAttrs(array_keys($definition['params']))); + } + + private function getResourcesKey() + { + $resourcesKey = $this->resourcesKey; + + if (!$resourcesKey) { + $class = substr(static::class, strrpos(static::class, '\\') + 1); + $resourcesKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class)) . 's'; + } + + return $resourcesKey; + } + + /** + * {@inheritDoc} + */ + public function enumerate(array $def, array $userVals = [], callable $mapFn = null) + { + $operation = $this->getOperation($def); + + $requestFn = function ($marker) use ($operation, $userVals) { + if ($marker) { + $userVals['marker'] = $marker; + } + return $this->sendRequest($operation, $userVals); + }; + + $resourceFn = function (array $data) { + $resource = $this->newInstance(); + $resource->populateFromArray($data); + return $resource; + }; + + $opts = [ + 'limit' => isset($userVals['limit']) ? $userVals['limit'] : null, + 'resourcesKey' => $this->getResourcesKey(), + 'markerKey' => $this->markerKey, + 'mapFn' => $mapFn, + ]; + + $iterator = new Iterator($opts, $requestFn, $resourceFn); + return $iterator(); + } + + public function extractMultipleInstances(ResponseInterface $response, $key = null) + { + $key = $key ?: $this->getResourcesKey(); + $resourcesData = Utils::jsonDecode($response)[$key]; + + $resources = []; + + foreach ($resourcesData as $resourceData) { + $resource = $this->newInstance(); + $resource->populateFromArray($resourceData); + $resources[] = $resource; + } + + return $resources; + } + + protected function getService() + { + $class = static::class; + $service = substr($class, 0, strpos($class, 'Models') - 1) . '\\Service'; + + return new $service($this->client, $this->api); + } +} |
