1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace OpenStack\Common\Resource; |
4
|
|
|
|
5
|
|
|
use OpenStack\Common\Api\OperatorInterface; |
6
|
|
|
use OpenStack\Common\Api\OperatorTrait; |
7
|
|
|
use OpenStack\Common\Transport\Utils; |
8
|
|
|
use Psr\Http\Message\ResponseInterface; |
9
|
|
|
|
10
|
|
|
abstract class OperatorResource extends AbstractResource implements OperatorInterface |
11
|
|
|
{ |
12
|
|
|
use OperatorTrait; |
13
|
|
|
|
14
|
|
|
const DEFAULT_MARKER_KEY = 'id'; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* The key that indicates how the API nests resource collections. For example, when |
18
|
|
|
* performing a GET, it could respond with ``{"servers": [{}, {}]}``. In this case, "servers" |
19
|
|
|
* is the resources key, since the array of servers is nested inside. |
20
|
|
|
* |
21
|
|
|
* @var string |
22
|
|
|
*/ |
23
|
|
|
protected $resourcesKey; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Indicates which attribute of the current resource should be used for pagination markers. |
27
|
|
|
* |
28
|
|
|
* @var string |
29
|
|
|
*/ |
30
|
|
|
protected $markerKey; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Will create a new instance of this class with the current HTTP client and API injected in. This |
34
|
|
|
* is useful when enumerating over a collection since multiple copies of the same resource class |
35
|
|
|
* are needed. |
36
|
|
|
* |
37
|
|
|
* @return OperatorResource |
38
|
|
|
*/ |
39
|
|
|
public function newInstance(): OperatorResource |
40
|
|
|
{ |
41
|
|
|
return new static($this->client, $this->api); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @return \GuzzleHttp\Psr7\Uri:null |
46
|
|
|
*/ |
47
|
|
|
protected function getHttpBaseUrl() |
48
|
|
|
{ |
49
|
|
|
return $this->client->getConfig('base_uri'); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param array $definition |
54
|
|
|
* |
55
|
|
|
* @return mixed |
56
|
|
|
*/ |
57
|
|
|
public function executeWithState(array $definition) |
58
|
|
|
{ |
59
|
|
|
return $this->execute($definition, $this->getAttrs(array_keys($definition['params']))); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
private function getResourcesKey(): string |
63
|
|
|
{ |
64
|
|
|
$resourcesKey = $this->resourcesKey; |
65
|
|
|
|
66
|
|
|
if (!$resourcesKey) { |
67
|
|
|
$class = substr(static::class, strrpos(static::class, '\\') + 1); |
68
|
|
|
$resourcesKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class)) . 's'; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
return $resourcesKey; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* {@inheritDoc} |
76
|
|
|
*/ |
77
|
|
|
public function enumerate(array $def, array $userVals = [], callable $mapFn = null): \Generator |
78
|
|
|
{ |
79
|
|
|
$operation = $this->getOperation($def); |
80
|
|
|
|
81
|
|
|
$requestFn = function ($marker) use ($operation, $userVals) { |
82
|
|
|
if ($marker) { |
83
|
|
|
$userVals['marker'] = $marker; |
84
|
|
|
} |
85
|
|
|
return $this->sendRequest($operation, $userVals); |
86
|
|
|
}; |
87
|
|
|
|
88
|
|
|
$resourceFn = function (array $data) { |
89
|
|
|
$resource = $this->newInstance(); |
90
|
|
|
$resource->populateFromArray($data); |
91
|
|
|
return $resource; |
92
|
|
|
}; |
93
|
|
|
|
94
|
|
|
$opts = [ |
95
|
|
|
'limit' => isset($userVals['limit']) ? $userVals['limit'] : null, |
96
|
|
|
'resourcesKey' => $this->getResourcesKey(), |
97
|
|
|
'markerKey' => $this->markerKey, |
98
|
|
|
'mapFn' => $mapFn, |
99
|
|
|
]; |
100
|
|
|
|
101
|
|
|
$iterator = new Iterator($opts, $requestFn, $resourceFn); |
102
|
|
|
return $iterator(); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
public function extractMultipleInstances(ResponseInterface $response, string $key = null): array |
106
|
|
|
{ |
107
|
|
|
$key = $key ?: $this->getResourcesKey(); |
108
|
|
|
$resourcesData = Utils::jsonDecode($response)[$key]; |
109
|
|
|
|
110
|
|
|
$resources = []; |
111
|
|
|
|
112
|
|
|
foreach ($resourcesData as $resourceData) { |
113
|
|
|
$resources[] = $this->newInstance()->populateFromArray($resourceData); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
return $resources; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
protected function getService() |
120
|
|
|
{ |
121
|
|
|
$class = static::class; |
122
|
|
|
$service = substr($class, 0, strpos($class, 'Models') - 1) . '\\Service'; |
123
|
|
|
|
124
|
|
|
return new $service($this->client, $this->api); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* {@inheritDoc} |
129
|
|
|
*/ |
130
|
|
View Code Duplication |
public function model(string $class, $data = null): ResourceInterface |
|
|
|
|
131
|
|
|
{ |
132
|
|
|
$model = new $class($this->client, $this->api); |
133
|
|
|
|
134
|
|
|
// @codeCoverageIgnoreStart |
135
|
|
|
if (!$model instanceof ResourceInterface) { |
136
|
|
|
throw new \RuntimeException(sprintf('%s does not implement %s', $class, ResourceInterface::class)); |
137
|
|
|
} |
138
|
|
|
// @codeCoverageIgnoreEnd |
139
|
|
|
|
140
|
|
|
if ($data instanceof ResponseInterface) { |
141
|
|
|
$model->populateFromResponse($data); |
142
|
|
|
} elseif (is_array($data)) { |
143
|
|
|
$model->populateFromArray($data); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
return $model; |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.