From c479658f0bb953ded4b29ca573404a318f1e798f Mon Sep 17 00:00:00 2001 From: EoleDev Date: Wed, 9 Mar 2016 15:36:02 +0100 Subject: New Library --- .../common/src/Common/Api/AbstractApi.php | 33 ++ .../common/src/Common/Api/AbstractParams.php | 100 ++++++ .../common/src/Common/Api/ApiInterface.php | 20 ++ .../common/src/Common/Api/Operation.php | 136 +++++++ .../common/src/Common/Api/Operator.php | 173 +++++++++ .../common/src/Common/Api/OperatorInterface.php | 51 +++ .../common/src/Common/Api/Parameter.php | 389 +++++++++++++++++++++ .../common/src/Common/ArrayAccessTrait.php | 67 ++++ .../common/src/Common/Auth/AuthHandler.php | 73 ++++ .../common/src/Common/Auth/Catalog.php | 20 ++ .../common/src/Common/Auth/IdentityService.php | 13 + .../php-opencloud/common/src/Common/Auth/Token.php | 15 + .../common/src/Common/Error/BadResponseError.php | 40 +++ .../common/src/Common/Error/BaseError.php | 12 + .../common/src/Common/Error/Builder.php | 179 ++++++++++ .../src/Common/Error/NotImplementedError.php | 12 + .../common/src/Common/Error/UserInputError.php | 12 + .../common/src/Common/HydratorStrategyTrait.php | 35 ++ .../php-opencloud/common/src/Common/JsonPath.php | 119 +++++++ .../common/src/Common/JsonSchema/JsonPatch.php | 115 ++++++ .../common/src/Common/JsonSchema/Schema.php | 72 ++++ .../src/Common/Resource/AbstractResource.php | 243 +++++++++++++ .../common/src/Common/Resource/Creatable.php | 19 + .../common/src/Common/Resource/Deletable.php | 18 + .../common/src/Common/Resource/HasMetadata.php | 67 ++++ .../common/src/Common/Resource/HasWaiterTrait.php | 124 +++++++ .../common/src/Common/Resource/Iterator.php | 97 +++++ .../common/src/Common/Resource/Listable.php | 28 ++ .../src/Common/Resource/ResourceInterface.php | 29 ++ .../common/src/Common/Resource/Retrievable.php | 18 + .../common/src/Common/Resource/Updateable.php | 18 + .../common/src/Common/Service/AbstractService.php | 14 + .../common/src/Common/Service/Builder.php | 170 +++++++++ .../common/src/Common/Service/ServiceInterface.php | 14 + .../common/src/Common/Transport/HandlerStack.php | 19 + .../common/src/Common/Transport/JsonSerializer.php | 95 +++++ .../common/src/Common/Transport/Middleware.php | 94 +++++ .../src/Common/Transport/RequestSerializer.php | 85 +++++ .../common/src/Common/Transport/Utils.php | 88 +++++ 39 files changed, 2926 insertions(+) create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/AbstractApi.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/AbstractParams.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/ApiInterface.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/Operation.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/Operator.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/OperatorInterface.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Api/Parameter.php create mode 100644 server/vendor/php-opencloud/common/src/Common/ArrayAccessTrait.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Auth/AuthHandler.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Auth/Catalog.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Auth/IdentityService.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Auth/Token.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Error/BadResponseError.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Error/BaseError.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Error/Builder.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Error/NotImplementedError.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Error/UserInputError.php create mode 100644 server/vendor/php-opencloud/common/src/Common/HydratorStrategyTrait.php create mode 100644 server/vendor/php-opencloud/common/src/Common/JsonPath.php create mode 100644 server/vendor/php-opencloud/common/src/Common/JsonSchema/JsonPatch.php create mode 100644 server/vendor/php-opencloud/common/src/Common/JsonSchema/Schema.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Creatable.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Deletable.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/HasMetadata.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/HasWaiterTrait.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Iterator.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Listable.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/ResourceInterface.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Retrievable.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Resource/Updateable.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Service/AbstractService.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Service/Builder.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Service/ServiceInterface.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Transport/HandlerStack.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Transport/JsonSerializer.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Transport/Middleware.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Transport/RequestSerializer.php create mode 100644 server/vendor/php-opencloud/common/src/Common/Transport/Utils.php (limited to 'server/vendor/php-opencloud/common/src') diff --git a/server/vendor/php-opencloud/common/src/Common/Api/AbstractApi.php b/server/vendor/php-opencloud/common/src/Common/Api/AbstractApi.php new file mode 100644 index 0000000..beee5e8 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Api/AbstractApi.php @@ -0,0 +1,33 @@ + true]); + } + + protected function notRequired(array $param) + { + return array_merge($param, ['required' => false]); + } + + protected function query(array $param) + { + return array_merge($param, ['location' => AbstractParams::QUERY]); + } + + protected function url(array $param) + { + return array_merge($param, ['location' => AbstractParams::URL]); + } + + public function documented(array $param) + { + return array_merge($param, ['required' => true]); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Api/AbstractParams.php b/server/vendor/php-opencloud/common/src/Common/Api/AbstractParams.php new file mode 100644 index 0000000..225e025 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Api/AbstractParams.php @@ -0,0 +1,100 @@ + self::INT_TYPE, + 'location' => 'query', + 'description' => << 'string', + 'location' => 'query', + 'description' => << sprintf("The unique ID, or identifier, for the %s", $type), + 'type' => self::STRING_TYPE, + 'location' => self::JSON, + ]; + } + + public function idPath() + { + return [ + 'type' => self::STRING_TYPE, + 'location' => self::URL, + 'description' => 'The unique ID of the resource', + ]; + } + + public function name($resource) + { + return [ + 'description' => sprintf("The name of the %s", $resource), + 'type' => self::STRING_TYPE, + 'location' => self::JSON, + ]; + } + + + public function sortDir() + { + return [ + 'type' => self::STRING_TYPE, + 'location' => self::QUERY, + 'description' => "Sorts by one or more sets of attribute and sort direction combinations.", + 'enum' => ['asc', 'desc'] + ]; + } + + public function sortKey() + { + return [ + 'type' => self::STRING_TYPE, + 'location' => self::QUERY, + 'description' => "Sorts by one or more sets of attribute and sort direction combinations.", + ]; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Api/ApiInterface.php b/server/vendor/php-opencloud/common/src/Common/Api/ApiInterface.php new file mode 100644 index 0000000..d5d26a0 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Api/ApiInterface.php @@ -0,0 +1,20 @@ +method = $definition['method']; + $this->path = $definition['path']; + + if (isset($definition['jsonKey'])) { + $this->jsonKey = $definition['jsonKey']; + } + + $this->params = self::toParamArray($definition['params']); + } + + /** + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * @return string + */ + public function getMethod() + { + return $this->method; + } + + /** + * Indicates whether this operation supports a parameter. + * + * @param $key The name of a parameter + * + * @return bool + */ + public function hasParam($key) + { + return isset($this->params[$key]); + } + + /** + * @param $name + * + * @return Parameter + */ + public function getParam($name) + { + return isset($this->params[$name]) ? $this->params[$name] : null; + } + + /** + * @return string + */ + public function getJsonKey() + { + return $this->jsonKey; + } + + /** + * A convenience method that will take a generic array of data and convert it into an array of + * {@see Parameter} objects. + * + * @param array $data A generic data array + * + * @return array + */ + public static function toParamArray(array $data) + { + $params = []; + + foreach ($data as $name => $param) { + $params[$name] = new Parameter($param + ['name' => $name]); + } + + return $params; + } + + /** + * This method will validate all of the user-provided values and throw an exception if any + * failures are detected. This is useful for basic sanity-checking before a request is + * serialized and sent to the API. + * + * @param array $userValues The user-defined values + * + * @return bool TRUE if validation passes + * @throws \Exception If validate fails + */ + public function validate(array $userValues) + { + foreach ($this->params as $paramName => $param) { + if (array_key_exists($paramName, $userValues)) { + $param->validate($userValues[$paramName]); + } elseif ($param->isRequired()) { + throw new \Exception(sprintf('"%s" is a required option, but it was not provided', $paramName)); + } + } + + return true; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Api/Operator.php b/server/vendor/php-opencloud/common/src/Common/Api/Operator.php new file mode 100644 index 0000000..4325b69 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Api/Operator.php @@ -0,0 +1,173 @@ +client = $client; + $this->api = $api; + } + + /** + * Magic method for dictating how objects are rendered when var_dump is called. + * For the benefit of users, extremely verbose and heavy properties (such as HTTP clients) are + * removed to provide easier access to normal state, such as resource attributes. + * + * @codeCoverageIgnore + * @return array + */ + public function __debugInfo() + { + $excludedVars = ['client', 'errorBuilder', 'api']; + + $output = []; + + foreach (get_object_vars($this) as $key => $val) { + if (!in_array($key, $excludedVars)) { + $output[$key] = $val; + } + } + + return $output; + } + + /** + * Retrieves a populated Operation according to the definition and values provided. A + * HTTP client is also injected into the object to allow it to communicate with the remote API. + * + * @param array $definition The data that dictates how the operation works + * + * @return Operation + */ + public function getOperation(array $definition) + { + return new Operation($definition); + } + + protected function sendRequest(Operation $operation, array $userValues = [], $async = false) + { + $operation->validate($userValues); + + $options = (new RequestSerializer)->serializeOptions($operation, $userValues); + $method = $async ? 'requestAsync' : 'request'; + $uri = uri_template($operation->getPath(), $userValues); + + return $this->client->$method($operation->getMethod(), $uri, $options); + } + + /** + * {@inheritDoc} + */ + public function execute(array $definition, array $userValues = []) + { + return $this->sendRequest($this->getOperation($definition), $userValues); + } + + /** + * {@inheritDoc} + */ + public function executeAsync(array $definition, array $userValues = []) + { + return $this->sendRequest($this->getOperation($definition), $userValues, true); + } + + /** + * {@inheritDoc} + */ + public function model($class, $data = null) + { + $model = new $class($this->client, $this->api); + + // @codeCoverageIgnoreStart + if (!$model instanceof ResourceInterface) { + throw new \RuntimeException(sprintf('%s does not implement %s', $class, ResourceInterface::class)); + } + // @codeCoverageIgnoreEnd + + if ($data instanceof ResponseInterface) { + $model->populateFromResponse($data); + } elseif (is_array($data)) { + $model->populateFromArray($data); + } + + return $model; + } + + /** + * Will create a new instance of this class with the current HTTP client and API injected in. This + * is useful when enumerating over a collection since multiple copies of the same resource class + * are needed. + * + * @return static + */ + public function newInstance() + { + return new static($this->client, $this->api); + } + + /** + * @return \GuzzleHttp\Psr7\Uri + */ + protected function getHttpBaseUrl() + { + return $this->client->getConfig('base_uri'); + } + + /** + * Magic method which intercepts async calls, finds the sequential version, and wraps it in a + * {@see Promise} object. In order for this to happen, the called methods need to be in the + * following format: `createAsync`, where `create` is the sequential method being wrapped. + * + * @param $methodName The name of the method being invoked. + * @param $args The arguments to be passed to the sequential method. + * + * @throws \RuntimeException If method does not exist + * + * @return Promise + */ + public function __call($methodName, $args) + { + $e = function ($name) { + return new \RuntimeException(sprintf('%s::%s is not defined', get_class($this), $name)); + }; + + if (substr($methodName, -5) === 'Async') { + $realMethod = substr($methodName, 0, -5); + if (!method_exists($this, $realMethod)) { + throw $e($realMethod); + } + + $promise = new Promise( + function () use (&$promise, $realMethod, $args) { + $value = call_user_func_array([$this, $realMethod], $args); + $promise->resolve($value); + } + ); + + return $promise; + } + + throw $e($methodName); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Api/OperatorInterface.php b/server/vendor/php-opencloud/common/src/Common/Api/OperatorInterface.php new file mode 100644 index 0000000..43c6ce2 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Api/OperatorInterface.php @@ -0,0 +1,51 @@ +hydrate($data); + + $this->required = (bool)$this->required; + + $this->stockLocation($data); + $this->stockItemSchema($data); + $this->stockProperties($data); + } + + private function stockLocation(array $data) + { + $this->location = isset($data['location']) ? $data['location'] : self::DEFAULT_LOCATION; + + if (!AbstractParams::isSupportedLocation($this->location)) { + throw new \RuntimeException(sprintf("%s is not a permitted location", $this->location)); + } + } + + private function stockItemSchema(array $data) + { + if (isset($data['items'])) { + $this->itemSchema = new Parameter($data['items']); + } + } + + private function stockProperties(array $data) + { + if (isset($data['properties'])) { + if (stripos($this->name, 'metadata') !== false) { + $this->properties = new Parameter($data['properties']); + } else { + foreach ($data['properties'] as $name => $property) { + $this->properties[$name] = new Parameter($property + ['name' => $name]); + } + } + } + } + + /** + * Retrieve the name that will be used over the wire. + * + * @return string + */ + public function getName() + { + return $this->sentAs ?: $this->name; + } + + /** + * Indicates whether the user must provide a value for this parameter. + * + * @return bool + */ + public function isRequired() + { + return $this->required === true; + } + + /** + * Validates a given user value and checks whether it passes basic sanity checking, such as types. + * + * @param $userValues The value provided by the user + * + * @return bool TRUE if the validation passes + * @throws \Exception If validation fails + */ + public function validate($userValues) + { + $this->validateEnums($userValues); + $this->validateType($userValues); + + if ($this->isArray()) { + $this->validateArray($userValues); + } elseif ($this->isObject()) { + $this->validateObject($userValues); + } + + return true; + } + + private function validateEnums($userValues) + { + if (!empty($this->enum) && $this->type == 'string' && !in_array($userValues, $this->enum)) { + throw new \Exception(sprintf( + 'The only permitted values are %s. You provided %s', implode(', ', $this->enum), print_r($userValues, true) + )); + } + } + + private function validateType($userValues) + { + if (!$this->hasCorrectType($userValues)) { + throw new \Exception(sprintf( + 'The key provided "%s" has the wrong value type. You provided %s (%s) but was expecting %s', + $this->name, print_r($userValues, true), gettype($userValues), $this->type + )); + } + } + + private function validateArray($userValues) + { + foreach ($userValues as $userValue) { + $this->itemSchema->validate($userValue); + } + } + + private function validateObject($userValues) + { + foreach ($userValues as $key => $userValue) { + $property = $this->getNestedProperty($key); + $property->validate($userValue); + } + } + + /** + * Internal method which retrieves a nested property for object parameters. + * + * @param $key The name of the child parameter + * + * @returns Parameter + * @throws \Exception + */ + private function getNestedProperty($key) + { + if (stripos($this->name, 'metadata') !== false && $this->properties instanceof Parameter) { + return $this->properties; + } elseif (isset($this->properties[$key])) { + return $this->properties[$key]; + } else { + throw new \Exception(sprintf('The key provided "%s" is not defined', $key)); + } + } + + /** + * Internal method which indicates whether the user value is of the same type as the one expected + * by this parameter. + * + * @param $userValue The value being checked + * + * @return bool + */ + private function hasCorrectType($userValue) + { + // Helper fn to see whether an array is associative (i.e. a JSON object) + $isAssociative = function ($value) { + return is_array($value) && array_keys($value) !== range(0, count($value) - 1); + }; + + // For params defined as objects, we'll let the user get away with + // passing in an associative array - since it's effectively a hash + if ($this->type == 'object' && $isAssociative($userValue)) { + return true; + } + + if (class_exists($this->type) || interface_exists($this->type)) { + return is_a($userValue, $this->type); + } + + if (!$this->type) { + return true; + } + + return gettype($userValue) == $this->type; + } + + /** + * Indicates whether this parameter represents an array type + * + * @return bool + */ + public function isArray() + { + return $this->type == 'array' && $this->itemSchema instanceof Parameter; + } + + /** + * Indicates whether this parameter represents an object type + * + * @return bool + */ + public function isObject() + { + return $this->type == 'object' && !empty($this->properties); + } + + public function getLocation() + { + return $this->location; + } + + /** + * Verifies whether the given location matches the parameter's location. + * + * @param $value + * + * @return bool + */ + public function hasLocation($value) + { + return $this->location == $value; + } + + /** + * Retrieves the parameter's path. + * + * @return string|null + */ + public function getPath() + { + return $this->path; + } + + /** + * Retrieves the common schema that an array parameter applies to all its child elements. + * + * @return Parameter + */ + public function getItemSchema() + { + return $this->itemSchema; + } + + /** + * Sets the name of the parameter to a new value + * + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Retrieves the child parameter for an object parameter. + * + * @param string $name The name of the child property + * + * @return null|Parameter + */ + public function getProperty($name) + { + if ($this->properties instanceof Parameter) { + $this->properties->setName($name); + return $this->properties; + } + + return isset($this->properties[$name]) ? $this->properties[$name] : null; + } + + /** + * Retrieves the prefix for a parameter, if any. + * + * @return string|null + */ + public function getPrefix() + { + return $this->prefix; + } + + public function getPrefixedName() + { + return $this->prefix . $this->getName(); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/ArrayAccessTrait.php b/server/vendor/php-opencloud/common/src/Common/ArrayAccessTrait.php new file mode 100644 index 0000000..72bcfce --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/ArrayAccessTrait.php @@ -0,0 +1,67 @@ +internalState[] = $value; + } else { + $this->internalState[$offset] = $value; + } + } + + /** + * Checks whether an internal key exists. + * + * @param string $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->internalState[$offset]); + } + + /** + * Unsets an internal key. + * + * @param string $offset + */ + public function offsetUnset($offset) + { + unset($this->internalState[$offset]); + } + + /** + * Retrieves an internal key. + * + * @param string $offset + * + * @return mixed|null + */ + public function offsetGet($offset) + { + return $this->offsetExists($offset) ? $this->internalState[$offset] : null; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Auth/AuthHandler.php b/server/vendor/php-opencloud/common/src/Common/Auth/AuthHandler.php new file mode 100644 index 0000000..1a36cc0 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Auth/AuthHandler.php @@ -0,0 +1,73 @@ +nextHandler = $nextHandler; + $this->tokenGenerator = $tokenGenerator; + $this->token = $token; + } + + /** + * This method is invoked before every HTTP request is sent to the API. When this happens, it + * checks to see whether a token is set and valid, and then sets the ``X-Auth-Token`` header + * for the HTTP request before letting it continue on its merry way. + * + * @param RequestInterface $request + * @param array $options + * + * @return mixed|void + */ + public function __invoke(RequestInterface $request, array $options) + { + $fn = $this->nextHandler; + + if ($this->shouldIgnore($request)) { + return $fn($request, $options); + } + + if (!$this->token || $this->token->hasExpired()) { + $this->token = call_user_func($this->tokenGenerator); + } + + $modify = ['set_headers' => ['X-Auth-Token' => $this->token->getId()]]; + + return $fn(modify_request($request, $modify), $options); + } + + /** + * Internal method which prevents infinite recursion. For certain requests, like the initial + * auth call itself, we do NOT want to send a token. + * + * @param RequestInterface $request + * + * @return bool + */ + private function shouldIgnore(RequestInterface $request) + { + return strpos((string) $request->getUri(), 'tokens') !== false && $request->getMethod() == 'POST'; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Auth/Catalog.php b/server/vendor/php-opencloud/common/src/Common/Auth/Catalog.php new file mode 100644 index 0000000..b4ab381 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Auth/Catalog.php @@ -0,0 +1,20 @@ +request = $request; + } + + public function setResponse(ResponseInterface $response) + { + $this->response = $response; + } + + public function getRequest() + { + return $this->request; + } + + public function getResponse() + { + return $this->response; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Error/BaseError.php b/server/vendor/php-opencloud/common/src/Common/Error/BaseError.php new file mode 100644 index 0000000..a7cb26e --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Error/BaseError.php @@ -0,0 +1,12 @@ +client = $client ?: new Client(); + } + + /** + * Internal method used when outputting headers in the error description. + * + * @param $name + * + * @return string + */ + private function header($name) + { + return sprintf("%s\n%s\n", $name, str_repeat('~', strlen($name))); + } + + /** + * Before outputting custom links, it is validated to ensure that the user is not + * directed off to a broken link. If a 404 is detected, it is hidden. + * + * @param $link The proposed link + * + * @return bool + */ + private function linkIsValid($link) + { + $link = $this->docDomain . $link; + + try { + return $this->client->request('HEAD', $link)->getStatusCode() < 400; + } catch (ClientException $e) { + return false; + } + } + + /** + * @param MessageInterface $message + * + * @codeCoverageIgnore + * @return string + */ + public function str(MessageInterface $message) + { + if ($message instanceof RequestInterface) { + $msg = trim($message->getMethod() . ' ' + . $message->getRequestTarget()) + . ' HTTP/' . $message->getProtocolVersion(); + if (!$message->hasHeader('host')) { + $msg .= "\r\nHost: " . $message->getUri()->getHost(); + } + } elseif ($message instanceof ResponseInterface) { + $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' + . $message->getStatusCode() . ' ' + . $message->getReasonPhrase(); + } + + foreach ($message->getHeaders() as $name => $values) { + $msg .= "\r\n{$name}: " . implode(', ', $values); + } + + if ($message->getBody()->getSize() < ini_get('memory_limit')) { + $msg .= "\r\n\r\n" . $message->getBody(); + } + + return $msg; + } + + /** + * Helper method responsible for constructing and returning {@see BadResponseError} exceptions. + * + * @param RequestInterface $request The faulty request + * @param ResponseInterface $response The error-filled response + * + * @return BadResponseError + */ + public function httpError(RequestInterface $request, ResponseInterface $response) + { + $message = $this->header('HTTP Error'); + + $message .= sprintf("The remote server returned a \"%d %s\" error for the following transaction:\n\n", + $response->getStatusCode(), $response->getReasonPhrase()); + + $message .= $this->header('Request'); + $message .= trim($this->str($request)) . PHP_EOL . PHP_EOL; + + $message .= $this->header('Response'); + $message .= trim($this->str($response)) . PHP_EOL . PHP_EOL; + + $message .= $this->header('Further information'); + $message .= $this->getStatusCodeMessage($response->getStatusCode()); + + $message .= "Visit http://docs.php-opencloud.com/en/latest/http-codes for more information about debugging " + . "HTTP status codes, or file a support issue on https://github.com/php-opencloud/openstack/issues."; + + $e = new BadResponseError($message); + $e->setRequest($request); + $e->setResponse($response); + + return $e; + } + + private function getStatusCodeMessage($statusCode) + { + $errors = [ + 400 => 'Please ensure that your input values are valid and well-formed. ', + 401 => 'Please ensure that your authentication credentials are valid. ', + 404 => "Please ensure that the resource you're trying to access actually exists. ", + 500 => 'Please try this operation again once you know the remote server is operational. ', + ]; + + return isset($errors[$statusCode]) ? $errors[$statusCode] : ''; + } + + /** + * Helper method responsible for constructing and returning {@see UserInputError} exceptions. + * + * @param string $expectedType The type that was expected from the user + * @param mixed $userValue The incorrect value the user actually provided + * @param string|null $furtherLink A link to further information if necessary (optional). + * + * @return UserInputError + */ + public function userInputError($expectedType, $userValue, $furtherLink = null) + { + $message = $this->header('User Input Error'); + + $message .= sprintf("%s was expected, but the following value was passed in:\n\n%s\n", + $expectedType, print_r($userValue, true)); + + $message .= "Please ensure that the value adheres to the expectation above. "; + + if ($furtherLink && $this->linkIsValid($furtherLink)) { + $message .= sprintf("Visit %s for more information about input arguments. ", $this->docDomain . $furtherLink); + } + + $message .= 'If you run into trouble, please open a support issue on https://github.com/php-opencloud/openstack/issues.'; + + return new UserInputError($message); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Error/NotImplementedError.php b/server/vendor/php-opencloud/common/src/Common/Error/NotImplementedError.php new file mode 100644 index 0000000..3e01d74 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Error/NotImplementedError.php @@ -0,0 +1,12 @@ + $val) { + $key = isset($aliases[$key]) ? $aliases[$key] : $key; + if (property_exists($this, $key)) { + $this->$key = $val; + } + } + } + + private function set($key, $property, array $data, callable $fn = null) + { + if (isset($data[$key]) && property_exists($this, $property)) { + $value = $fn ? call_user_func($fn, $data[$key]) : $data[$key]; + $this->$property = $value; + } + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/JsonPath.php b/server/vendor/php-opencloud/common/src/Common/JsonPath.php new file mode 100644 index 0000000..0a6372e --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/JsonPath.php @@ -0,0 +1,119 @@ +['foo' => ['bar' => ['baz' => 'some_value']]] + * + * and you wanted to insert or extract an element. Usually, you would use: + * + *
$array['foo']['bar']['baz'] = 'new_value';
+ * + * but sometimes you do not have access to the variable - so a string representation is needed. Using + * XPath-like syntax, this class allows you to do this: + * + *
$jsonPath = new JsonPath($array);
+ * $jsonPath->set('foo.bar.baz', 'new_value');
+ * $val = $jsonPath->get('foo.bar.baz');
+ * 
+ * + * @package OpenCloud\Common + */ +class JsonPath +{ + /** @var array */ + private $jsonStructure; + + /** + * @param $structure The initial data structure to extract from and insert into. Typically this will be a + * multidimensional associative array; but well-formed JSON strings are also acceptable. + */ + public function __construct($structure) + { + $this->jsonStructure = is_string($structure) ? json_decode($structure, true) : $structure; + } + + /** + * Set a node in the structure + * + * @param $path The XPath to use + * @param $value The new value of the node + */ + public function set($path, $value) + { + $this->jsonStructure = $this->setPath($path, $value, $this->jsonStructure); + } + + /** + * Internal method for recursive calls. + * + * @param $path + * @param $value + * @param $json + * @return mixed + */ + private function setPath($path, $value, $json) + { + $nodes = explode('.', $path); + $point = array_shift($nodes); + + if (!isset($json[$point])) { + $json[$point] = []; + } + + if (!empty($nodes)) { + $json[$point] = $this->setPath(implode('.', $nodes), $value, $json[$point]); + } else { + $json[$point] = $value; + } + + return $json; + } + + /** + * Return the updated structure. + * + * @return mixed + */ + public function getStructure() + { + return $this->jsonStructure; + } + + /** + * Get a path's value. If no path can be matched, NULL is returned. + * + * @param $path + * @return mixed|null + */ + public function get($path) + { + return $this->getPath($path, $this->jsonStructure); + } + + /** + * Internal method for recursion. + * + * @param $path + * @param $json + * @return null + */ + private function getPath($path, $json) + { + $nodes = explode('.', $path); + $point = array_shift($nodes); + + if (!isset($json[$point])) { + return null; + } + + if (empty($nodes)) { + return $json[$point]; + } else { + return $this->getPath(implode('.', $nodes), $json[$point]); + } + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/JsonSchema/JsonPatch.php b/server/vendor/php-opencloud/common/src/Common/JsonSchema/JsonPatch.php new file mode 100644 index 0000000..2c12ec0 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/JsonSchema/JsonPatch.php @@ -0,0 +1,115 @@ +makeDiff($src, $dest); + } + + public function makeDiff($srcStruct, $desStruct, $path = '') + { + $changes = []; + + if (is_object($srcStruct)) { + $changes = $this->handleObject($srcStruct, $desStruct, $path); + } elseif (is_array($srcStruct)) { + $changes = $this->handleArray($srcStruct, $desStruct, $path); + } elseif ($srcStruct != $desStruct) { + $changes[] = $this->makePatch(self::OP_REPLACE, $path, $desStruct); + } + + return $changes; + } + + protected function handleArray($srcStruct, $desStruct, $path) + { + $changes = []; + + if ($diff = $this->arrayDiff($desStruct, $srcStruct)) { + foreach ($diff as $key => $val) { + if (is_object($val)) { + $changes = array_merge($changes, $this->makeDiff($srcStruct[$key], $val, $this->path($path, $key))); + } else { + $op = array_key_exists($key, $srcStruct) && !in_array($srcStruct[$key], $desStruct, true) + ? self::OP_REPLACE : self::OP_ADD; + $changes[] = $this->makePatch($op, $this->path($path, $key), $val); + } + } + } elseif ($srcStruct != $desStruct) { + foreach ($srcStruct as $key => $val) { + if (!in_array($val, $desStruct, true)) { + $changes[] = $this->makePatch(self::OP_REMOVE, $this->path($path, $key)); + } + } + } + + return $changes; + } + + protected function handleObject($srcStruct, $desStruct, $path) + { + $changes = []; + + if ($this->shouldPartiallyReplace($srcStruct, $desStruct)) { + foreach ($desStruct as $key => $val) { + if (!property_exists($srcStruct, $key)) { + $changes[] = $this->makePatch(self::OP_ADD, $this->path($path, $key), $val); + } elseif ($srcStruct->$key != $val) { + $changes = array_merge($changes, $this->makeDiff($srcStruct->$key, $val, $this->path($path, $key))); + } + } + } elseif ($this->shouldPartiallyReplace($desStruct, $srcStruct)) { + foreach ($srcStruct as $key => $val) { + if (!property_exists($desStruct, $key)) { + $changes[] = $this->makePatch(self::OP_REMOVE, $this->path($path, $key)); + } + } + } + + return $changes; + } + + protected function shouldPartiallyReplace($o1, $o2) + { + return count(array_diff_key((array) $o1, (array) $o2)) < count($o1); + } + + protected function arrayDiff(array $a1, array $a2) + { + $result = []; + + foreach ($a1 as $key => $val) { + if (!in_array($val, $a2, true)) { + $result[$key] = $val; + } + } + + return $result; + } + + protected function path($root, $path) + { + if ($path === '_empty_') { + $path = ''; + } + + return rtrim($root, '/') . '/' . ltrim($path, '/'); + } + + protected function makePatch($op, $path, $val = null) + { + switch ($op) { + default: + return ['op' => $op, 'path' => $path, 'value' => $val]; + case self::OP_REMOVE: + return ['op' => $op, 'path' => $path]; + } + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/JsonSchema/Schema.php b/server/vendor/php-opencloud/common/src/Common/JsonSchema/Schema.php new file mode 100644 index 0000000..a1cd380 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/JsonSchema/Schema.php @@ -0,0 +1,72 @@ +body = (object) $body; + $this->validator = $validator ?: new Validator(); + } + + public function getPropertyPaths() + { + $paths = []; + + foreach ($this->body->properties as $propertyName => $property) { + $paths[] = sprintf("/%s", $propertyName); + } + + return $paths; + } + + public function normalizeObject($subject, array $aliases) + { + $out = new \stdClass; + + foreach ($this->body->properties as $propertyName => $property) { + $name = isset($aliases[$propertyName]) ? $aliases[$propertyName] : $propertyName; + if (isset($property->readOnly) && $property->readOnly === true) { + continue; + } elseif (property_exists($subject, $name)) { + $out->$propertyName = $subject->$name; + } elseif (property_exists($subject, $propertyName)) { + $out->$propertyName = $subject->$propertyName; + } + } + + return $out; + } + + public function validate($data) + { + $this->validator->check($data, $this->body); + } + + public function isValid() + { + return $this->validator->isValid(); + } + + public function getErrors() + { + return $this->validator->getErrors(); + } + + public function getErrorString() + { + $msg = "Provided values do not validate. Errors:\n"; + + foreach ($this->getErrors() as $error) { + $msg .= sprintf("[%s] %s\n", $error['property'], $error['message']); + } + + return $msg; + } +} 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 @@ + '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 @@ + '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 @@ +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 @@ +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 @@ + 'publicURL']; + + /** + * @param array $globalOptions Options that will be applied to every service created by this builder. + * Eventually they will be merged (and if necessary overridden) by the + * service-specific options passed in. + */ + public function __construct(array $globalOptions = [], $rootNamespace = 'OpenCloud') + { + $this->globalOptions = $globalOptions; + $this->rootNamespace = $rootNamespace; + } + + /** + * Internal method which resolves the API and Service classes for a service. + * + * @param string $serviceName The name of the service, e.g. Compute + * @param int $serviceVersion The major version of the service, e.g. 2 + * + * @return array + */ + private function getClasses($serviceName, $serviceVersion) + { + $rootNamespace = sprintf("%s\\%s\\v%d", $this->rootNamespace, $serviceName, $serviceVersion); + + return [ + sprintf("%s\\Api", $rootNamespace), + sprintf("%s\\Service", $rootNamespace), + ]; + } + + /** + * This method will return an OpenCloud service ready fully built and ready for use. There is + * some initial setup that may prohibit users from directly instantiating the service class + * directly - this setup includes the configuration of the HTTP client's base URL, and the + * attachment of an authentication handler. + * + * @param $serviceName The name of the service as it appears in the OpenCloud\* namespace + * @param $serviceVersion The major version of the service + * @param array $serviceOptions The service-specific options to use + * + * @return \OpenCloud\Common\Service\ServiceInterface + * + * @throws \Exception + */ + public function createService($serviceName, $serviceVersion, array $serviceOptions = []) + { + $options = $this->mergeOptions($serviceOptions); + + $this->stockIdentityService($options); + $this->stockAuthHandler($options); + $this->stockHttpClient($options, $serviceName); + + list($apiClass, $serviceClass) = $this->getClasses($serviceName, $serviceVersion); + + return new $serviceClass($options['httpClient'], new $apiClass()); + } + + private function stockHttpClient(array &$options, $serviceName) + { + if (!isset($options['httpClient']) || !($options['httpClient'] instanceof ClientInterface)) { + if (strcasecmp($serviceName, 'identity') === 0) { + $baseUrl = $options['authUrl']; + $stack = $this->getStack($options['authHandler']); + } else { + list($token, $baseUrl) = $options['identityService']->authenticate($options); + $stack = $this->getStack($options['authHandler'], $token); + } + + $this->addDebugMiddleware($options, $stack); + + $options['httpClient'] = $this->httpClient($baseUrl, $stack); + } + } + + /** + * @codeCoverageIgnore + */ + private function addDebugMiddleware(array $options, HandlerStack &$stack) + { + if (!empty($options['debugLog']) + && !empty($options['logger']) + && !empty($options['messageFormatter']) + ) { + $stack->push(GuzzleMiddleware::log($options['logger'], $options['messageFormatter'])); + } + } + + private function stockIdentityService(array &$options) + { + if (!isset($options['identityService'])) { + $httpClient = $this->httpClient($options['authUrl'], HandlerStack::create()); + $options['identityService'] = Service::factory($httpClient); + } + } + + /** + * @param array $options + * @codeCoverageIgnore + */ + private function stockAuthHandler(array &$options) + { + if (!isset($options['authHandler'])) { + $options['authHandler'] = function () use ($options) { + return $options['identityService']->generateToken($options); + }; + } + } + + private function getStack(callable $authHandler, Token $token = null) + { + $stack = HandlerStack::create(); + $stack->push(Middleware::authHandler($authHandler, $token)); + return $stack; + } + + private function httpClient($baseUrl, HandlerStack $stack) + { + return new Client([ + 'base_uri' => Utils::normalizeUrl($baseUrl), + 'handler' => $stack, + ]); + } + + private function mergeOptions(array $serviceOptions) + { + $options = array_merge($this->defaults, $this->globalOptions, $serviceOptions); + + if (!isset($options['authUrl'])) { + throw new \InvalidArgumentException('"authUrl" is a required option'); + } + + return $options; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Service/ServiceInterface.php b/server/vendor/php-opencloud/common/src/Common/Service/ServiceInterface.php new file mode 100644 index 0000000..6ad3089 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Service/ServiceInterface.php @@ -0,0 +1,14 @@ +push(Middleware::httpErrors()); + $stack->push(Middleware::prepareBody()); + + return $stack; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Transport/JsonSerializer.php b/server/vendor/php-opencloud/common/src/Common/Transport/JsonSerializer.php new file mode 100644 index 0000000..11b31d3 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Transport/JsonSerializer.php @@ -0,0 +1,95 @@ +getName(); + if ($path = $param->getPath()) { + $jsonPath = new JsonPath($json); + $jsonPath->set(sprintf("%s.%s", $path, $name), $userValue); + $json = $jsonPath->getStructure(); + } elseif ($name) { + $json[$name] = $userValue; + } else { + $json[] = $userValue; + } + + return $json; + } + + /** + * Populates a value into an array-like structure. + * + * @param Parameter $param The schema that defines how the JSON field is being populated + * @param mixed $userValue The user value that is populating a JSON field + * + * @return array|mixed + */ + private function stockArrayJson(Parameter $param, $userValue) + { + $elems = []; + foreach ($userValue as $item) { + $elems = $this->stockJson($param->getItemSchema(), $item, $elems); + } + return $elems; + } + + /** + * Populates a value into an object-like structure. + * + * @param Parameter $param The schema that defines how the JSON field is being populated + * @param mixed $userValue The user value that is populating a JSON field + * + * @return array + */ + private function stockObjectJson(Parameter $param, $userValue) + { + $object = []; + foreach ($userValue as $key => $val) { + $object = $this->stockJson($param->getProperty($key), $val, $object); + } + return $object; + } + + /** + * A generic method that will populate a JSON structure with a value according to a schema. It + * supports multiple types and will delegate accordingly. + * + * @param Parameter $param The schema that defines how the JSON field is being populated + * @param mixed $userValue The user value that is populating a JSON field + * @param array $json The existing JSON structure that will be populated + * + * @return array + */ + public function stockJson(Parameter $param, $userValue, $json) + { + if ($param->isArray()) { + $userValue = $this->stockArrayJson($param, $userValue); + } elseif ($param->isObject()) { + $userValue = $this->stockObjectJson($param, $userValue); + } + // Populate the final value + return $this->stockValue($param, $userValue, $json); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Transport/Middleware.php b/server/vendor/php-opencloud/common/src/Common/Transport/Middleware.php new file mode 100644 index 0000000..916ff22 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Transport/Middleware.php @@ -0,0 +1,94 @@ +then( + function (ResponseInterface $response) use ($request, $handler) { + if ($response->getStatusCode() < 400) { + return $response; + } + throw (new Builder())->httpError($request, $response); + } + ); + }; + }; + } + + /** + * @param callable $tokenGenerator + * @param Token $token + * + * @return callable + */ + public static function authHandler(callable $tokenGenerator, Token $token = null) + { + return function (callable $handler) use ($tokenGenerator, $token) { + return new AuthHandler($handler, $tokenGenerator, $token); + }; + } + + /** + * @codeCoverageIgnore + */ + public static function history(array &$container) + { + return GuzzleMiddleware::history($container); + } + + /** + * @codeCoverageIgnore + */ + public static function retry(callable $decider, callable $delay = null) + { + return GuzzleMiddleware::retry($decider, $delay); + } + + /** + * @codeCoverageIgnore + */ + public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO) + { + return GuzzleMiddleware::log($logger, $formatter, $logLevel); + } + + /** + * @codeCoverageIgnore + */ + public static function prepareBody() + { + return GuzzleMiddleware::prepareBody(); + } + + /** + * @codeCoverageIgnore + */ + public static function mapRequest(callable $fn) + { + return GuzzleMiddleware::mapRequest($fn); + } + + /** + * @codeCoverageIgnore + */ + public static function mapResponse(callable $fn) + { + return GuzzleMiddleware::mapResponse($fn); + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Transport/RequestSerializer.php b/server/vendor/php-opencloud/common/src/Common/Transport/RequestSerializer.php new file mode 100644 index 0000000..30f04af --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Transport/RequestSerializer.php @@ -0,0 +1,85 @@ +jsonSerializer = $jsonSerializer ?: new JsonSerializer(); + } + + public function serializeOptions(Operation $operation, array $userValues = []) + { + $options = ['headers' => []]; + + foreach ($userValues as $paramName => $paramValue) { + if (null === ($schema = $operation->getParam($paramName))) { + continue; + } + + $method = sprintf('stock%s', ucfirst($schema->getLocation())); + $this->$method($schema, $paramValue, $options); + } + + if (!empty($options['json'])) { + if ($key = $operation->getJsonKey()) { + $options['json'] = [$key => $options['json']]; + } + if (strpos(json_encode($options['json']), '\/') !== false) { + $options['body'] = json_encode($options['json'], JSON_UNESCAPED_SLASHES); + $options['headers']['Content-Type'] = 'application/json'; + unset($options['json']); + } + } + + return $options; + } + + private function stockUrl() + { + } + + private function stockQuery(Parameter $schema, $paramValue, array &$options) + { + $options['query'][$schema->getName()] = $paramValue; + } + + private function stockHeader(Parameter $schema, $paramValue, array &$options) + { + $paramName = $schema->getName(); + + if (stripos($paramName, 'metadata') !== false) { + return $this->stockMetadataHeader($schema, $paramValue, $options); + } + + $options['headers'] += is_scalar($paramValue) ? [$schema->getPrefixedName() => $paramValue] : []; + } + + private function stockMetadataHeader(Parameter $schema, $paramValue, array &$options) + { + foreach ($paramValue as $key => $keyVal) { + $schema = $schema->getItemSchema() ?: new Parameter(['prefix' => $schema->getPrefix(), 'name' => $key]); + $this->stockHeader($schema, $keyVal, $options); + } + } + + private function stockJson(Parameter $schema, $paramValue, array &$options) + { + $json = isset($options['json']) ? $options['json'] : []; + $options['json'] = $this->jsonSerializer->stockJson($schema, $paramValue, $json); + } + + private function stockRaw(Parameter $schema, $paramValue, array &$options) + { + $options['body'] = $paramValue; + } +} diff --git a/server/vendor/php-opencloud/common/src/Common/Transport/Utils.php b/server/vendor/php-opencloud/common/src/Common/Transport/Utils.php new file mode 100644 index 0000000..c2a2dc1 --- /dev/null +++ b/server/vendor/php-opencloud/common/src/Common/Transport/Utils.php @@ -0,0 +1,88 @@ + 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', + JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' + ]; + + $responseBody = (string) $response->getBody(); + + if (strlen($responseBody) === 0) { + return $responseBody; + } + + $data = json_decode($responseBody, $assoc); + + if (JSON_ERROR_NONE !== json_last_error()) { + $last = json_last_error(); + throw new \InvalidArgumentException( + 'Unable to parse JSON data: ' . (isset($jsonErrors[$last]) ? $jsonErrors[$last] : 'Unknown error') + ); + } + + return $data; + } + + /** + * Method for flattening a nested array. + * + * @param array $data The nested array + * @param null $key The key to extract + * + * @return array + */ + public static function flattenJson($data, $key = null) + { + return (!empty($data) && $key && isset($data[$key])) ? $data[$key] : $data; + } + + /** + * Method for normalize an URL string. + * + * Append the http:// prefix if not present, and add a + * closing url separator when missing. + * + * @param string $url The url representation. + * + * @return string + */ + public static function normalizeUrl($url) + { + if (strpos($url, 'http') === false) { + $url = 'http://' . $url; + } + + return rtrim($url, '/') . '/'; + } + + /** + * Add an unlimited list of paths to a given URI. + * + * @param UriInterface $uri + * @param ...$paths + * + * @return UriInterface + */ + public static function addPaths(UriInterface $uri, ...$paths) + { + return uri_for(rtrim((string) $uri, '/') . '/' . implode('/', $paths)); + } + + public static function appendPath(UriInterface $uri, $path) + { + return uri_for(rtrim((string) $uri, '/') . '/' . $path); + } +} -- cgit v1.2.3