New Library
This commit is contained in:
parent
5c6f6c97b7
commit
c479658f0b
83 changed files with 5788 additions and 0 deletions
243
server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php
vendored
Normal file
243
server/vendor/php-opencloud/common/src/Common/Resource/AbstractResource.php
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue