summaryrefslogtreecommitdiff
path: root/server/vendor/php-opencloud/common/src/Common/Resource
diff options
context:
space:
mode:
Diffstat (limited to 'server/vendor/php-opencloud/common/src/Common/Resource')
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php243
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Creatable.php19
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Deletable.php18
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/HasMetadata.php67
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/HasWaiterTrait.php124
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Iterator.php97
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Listable.php28
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/ResourceInterface.php29
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Retrievable.php18
-rw-r--r--server/vendor/php-opencloud/common/src/Common/Resource/Updateable.php18
10 files changed, 661 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);
+ }
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Creatable.php b/server/vendor/php-opencloud/common/src/Common/Resource/Creatable.php
new file mode 100644
index 0000000..19579c1
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Creatable.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+/**
+ * Represents a resource that can be created.
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface Creatable
+{
+ /**
+ * Create a new resource according to the configuration set in the options.
+ *
+ * @param array $userOptions
+ * @return self
+ */
+ public function create(array $userOptions);
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Deletable.php b/server/vendor/php-opencloud/common/src/Common/Resource/Deletable.php
new file mode 100644
index 0000000..eeb0602
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Deletable.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+/**
+ * Represents a resource that can be deleted.
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface Deletable
+{
+ /**
+ * Permanently delete this resource.
+ *
+ * @return void
+ */
+ public function delete();
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/HasMetadata.php b/server/vendor/php-opencloud/common/src/Common/Resource/HasMetadata.php
new file mode 100644
index 0000000..53b51fc
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/HasMetadata.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+use Psr\Http\Message\ResponseInterface;
+
+interface HasMetadata
+{
+ /**
+ * Retrieves the metadata for the resource in the form of an associative array or hash. Each key represents the
+ * metadata item's name, and each value represents the metadata item's remote value.
+ *
+ * @return array
+ */
+ public function getMetadata();
+
+ /**
+ * Merges a set of new values with those which already exist (on the remote API) for a resource. For example, if
+ * the resource has this metadata already set:
+ *
+ * Foo: val1
+ * Bar: val2
+ *
+ * and mergeMetadata(['Foo' => 'val3', 'Baz' => 'val4']); is called, then the resource will have the following
+ * metadata:
+ *
+ * Foo: val3
+ * Bar: val2
+ * Baz: val4
+ *
+ * You will notice that any metadata items which are not specified in the call are preserved.
+ *
+ * @param array $metadata The new metadata items
+ *
+ * @return mixed
+ */
+ public function mergeMetadata(array $metadata);
+
+ /**
+ * Replaces all of the existing metadata items for a resource with a new set of values. Any metadata items which
+ * are not provided in the call are removed from the resource. For example, if the resource has this metadata
+ * already set:
+ *
+ * Foo: val1
+ * Bar: val2
+ *
+ * and resetMetadata(['Foo' => 'val3', 'Baz' => 'val4']); is called, then the resource will have the following
+ * metadata:
+ *
+ * Foo: val3
+ * Baz: val4
+ *
+ * @param array $metadata The new metadata items
+ *
+ * @return mixed
+ */
+ public function resetMetadata(array $metadata);
+
+ /**
+ * Extracts metadata from a response object and returns it in the form of an associative array.
+ *
+ * @param ResponseInterface $response
+ *
+ * @return array
+ */
+ public function parseMetadata(ResponseInterface $response);
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/HasWaiterTrait.php b/server/vendor/php-opencloud/common/src/Common/Resource/HasWaiterTrait.php
new file mode 100644
index 0000000..519be7e
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/HasWaiterTrait.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+use OpenCloud\Common\Error\BadResponseError;
+
+/**
+ * Contains reusable functionality for resources that have long operations which require waiting in
+ * order to reach a particular state.
+ *
+ * @codeCoverageIgnore
+ *
+ * @package OpenCloud\Common\Resource
+ */
+trait HasWaiterTrait
+{
+ /**
+ * Provides a blocking operation until the resource has reached a particular state. The method
+ * will enter a loop, requesting feedback from the remote API until it sends back an appropriate
+ * status.
+ *
+ * @param string $status The state to be reached
+ * @param int $timeout The maximum timeout. If the total time taken by the waiter has reached
+ * or exceed this timeout, the blocking operation will immediately cease.
+ * @param int $sleepPeriod The amount of time to pause between each HTTP request.
+ */
+ public function waitUntil($status, $timeout = 60, $sleepPeriod = 1)
+ {
+ $startTime = time();
+
+ while (true) {
+ $this->retrieve();
+
+ if ($this->status == $status || $this->shouldHalt($timeout, $startTime)) {
+ break;
+ }
+
+ sleep($sleepPeriod);
+ }
+ }
+
+ /**
+ * Provides a blocking operation until the resource has reached a particular state. The method
+ * will enter a loop, executing the callback until TRUE is returned. This provides great
+ * flexibility.
+ *
+ * @param callable $fn An anonymous function that will be executed on every iteration. You can
+ * encapsulate your own logic to determine whether the resource has
+ * successfully transitioned. When TRUE is returned by the callback,
+ * the loop will end.
+ * @param int|bool $timeout The maximum timeout in seconds. If the total time taken by the waiter has reached
+ * or exceed this timeout, the blocking operation will immediately cease. If FALSE
+ * is provided, the timeout will never be considered.
+ * @param int $sleepPeriod The amount of time to pause between each HTTP request.
+ */
+ public function waitWithCallback(callable $fn, $timeout = 60, $sleepPeriod = 1)
+ {
+ $startTime = time();
+
+ while (true) {
+ $this->retrieve();
+
+ $response = call_user_func_array($fn, [$this]);
+
+ if ($response === true || $this->shouldHalt($timeout, $startTime)) {
+ break;
+ }
+
+ sleep($sleepPeriod);
+ }
+ }
+
+ /**
+ * Internal method used to identify whether a timeout has been exceeded.
+ *
+ * @param bool|int $timeout
+ * @param int $startTime
+ *
+ * @return bool
+ */
+ private function shouldHalt($timeout, $startTime)
+ {
+ if ($timeout === false) {
+ return false;
+ }
+
+ return time() - $startTime >= $timeout;
+ }
+
+ /**
+ * Convenience method providing a blocking operation until the resource transitions to an
+ * ``ACTIVE`` status.
+ *
+ * @param int|bool $timeout The maximum timeout in seconds. If the total time taken by the waiter has reached
+ * or exceed this timeout, the blocking operation will immediately cease. If FALSE
+ * is provided, the timeout will never be considered.
+ */
+ public function waitUntilActive($timeout = false)
+ {
+ $this->waitUntil('ACTIVE', $timeout);
+ }
+
+ public function waitUntilDeleted($timeout = 60, $sleepPeriod = 1)
+ {
+ $startTime = time();
+
+ while (true) {
+ try {
+ $this->retrieve();
+ } catch (BadResponseError $e) {
+ if ($e->getResponse()->getStatusCode() === 404) {
+ break;
+ }
+ throw $e;
+ }
+
+ if ($this->shouldHalt($timeout, $startTime)) {
+ break;
+ }
+
+ sleep($sleepPeriod);
+ }
+ }
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Iterator.php b/server/vendor/php-opencloud/common/src/Common/Resource/Iterator.php
new file mode 100644
index 0000000..63d4455
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Iterator.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+use OpenCloud\Common\Transport\Utils;
+
+class Iterator
+{
+ private $requestFn;
+ private $resourceFn;
+ private $limit;
+ private $count;
+ private $resourcesKey;
+ private $markerKey;
+ private $mapFn;
+ private $currentMarker;
+
+ public function __construct(array $options, callable $requestFn, callable $resourceFn)
+ {
+ $this->limit = isset($options['limit']) ? $options['limit'] : false;
+ $this->count = 0;
+
+ if (isset($options['resourcesKey'])) {
+ $this->resourcesKey = $options['resourcesKey'];
+ }
+
+ if (isset($options['markerKey'])) {
+ $this->markerKey = $options['markerKey'];
+ }
+
+ if (isset($options['mapFn']) && is_callable($options['mapFn'])) {
+ $this->mapFn = $options['mapFn'];
+ }
+
+ $this->requestFn = $requestFn;
+ $this->resourceFn = $resourceFn;
+ }
+
+ private function fetchResources()
+ {
+ if ($this->shouldNotSendAnotherRequest()) {
+ return false;
+ }
+
+ $response = call_user_func($this->requestFn, $this->currentMarker);
+
+ $json = Utils::flattenJson(Utils::jsonDecode($response), $this->resourcesKey);
+
+ if ($response->getStatusCode() === 204 || empty($json)) {
+ return false;
+ }
+
+ return $json;
+ }
+
+ private function assembleResource(array $data)
+ {
+ $resource = call_user_func($this->resourceFn, $data);
+
+ // Invoke user-provided fn if provided
+ if ($this->mapFn) {
+ call_user_func_array($this->mapFn, [&$resource]);
+ }
+
+ // Update marker if operation supports it
+ if ($this->markerKey) {
+ $this->currentMarker = $resource->{$this->markerKey};
+ }
+
+ return $resource;
+ }
+
+ private function totalReached()
+ {
+ return $this->limit && $this->count >= $this->limit;
+ }
+
+ private function shouldNotSendAnotherRequest()
+ {
+ return $this->totalReached() || ($this->count > 0 && !$this->markerKey);
+ }
+
+ public function __invoke()
+ {
+ while ($resources = $this->fetchResources()) {
+ foreach ($resources as $resourceData) {
+ if ($this->totalReached()) {
+ break;
+ }
+
+ $this->count++;
+
+ yield $this->assembleResource($resourceData);
+ }
+ }
+ }
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Listable.php b/server/vendor/php-opencloud/common/src/Common/Resource/Listable.php
new file mode 100644
index 0000000..8e255c0
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Listable.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+/**
+ * Represents a resource that can be enumerated (listed over).
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface Listable
+{
+ /**
+ * This method iterates over a collection of resources. It sends the operation's request to the API,
+ * parses the response, converts each element into {@see self} and - if pagination is supported - continues
+ * to send requests until an empty collection is received back.
+ *
+ * For paginated collections, it sends subsequent requests according to a marker URL query. The value
+ * of the marker will depend on the last element returned in the previous response. If a limit is
+ * provided, the loop will continue up until that point.
+ *
+ * @param array $def The operation definition
+ * @param array $userVals The user values
+ * @param callable $mapFn An optional callback that will be executed on every resource iteration.
+ *
+ * @returns void
+ */
+ public function enumerate(array $def, array $userVals = [], callable $mapFn = null);
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/ResourceInterface.php b/server/vendor/php-opencloud/common/src/Common/Resource/ResourceInterface.php
new file mode 100644
index 0000000..8cf841b
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/ResourceInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Represents an API resource.
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface ResourceInterface
+{
+ /**
+ * All models which represent an API resource should be able to be populated
+ * from a {@see ResponseInterface} object.
+ *
+ * @param ResponseInterface $response
+ *
+ * @return self
+ */
+ public function populateFromResponse(ResponseInterface $response);
+
+ /**
+ * @param array $data
+ * @return mixed
+ */
+ public function populateFromArray(array $data);
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Retrievable.php b/server/vendor/php-opencloud/common/src/Common/Resource/Retrievable.php
new file mode 100644
index 0000000..333b2c2
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Retrievable.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+/**
+ * A resource that supports a GET or HEAD operation to retrieve more details.
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface Retrievable
+{
+ /**
+ * Retrieve details of the current resource from the remote API.
+ *
+ * @return void
+ */
+ public function retrieve();
+}
diff --git a/server/vendor/php-opencloud/common/src/Common/Resource/Updateable.php b/server/vendor/php-opencloud/common/src/Common/Resource/Updateable.php
new file mode 100644
index 0000000..a9a3f0e
--- /dev/null
+++ b/server/vendor/php-opencloud/common/src/Common/Resource/Updateable.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace OpenCloud\Common\Resource;
+
+/**
+ * Represents a resource that can be updated.
+ *
+ * @package OpenCloud\Common\Resource
+ */
+interface Updateable
+{
+ /**
+ * Update the current resource with the configuration set out in the user options.
+ *
+ * @return void
+ */
+ public function update();
+}