GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 7642f8...15f213 )
by Jamie
07:09 queued 01:51
created

AbstractResource   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 13
Bugs 0 Features 3
Metric Value
wmc 34
c 13
b 0
f 3
lcom 1
cbo 4
dl 0
loc 227
ccs 101
cts 101
cp 1
rs 9.2

12 Methods

Rating   Name   Duplication   Size   Complexity  
A executeWithState() 0 4 1
A getAttrs() 0 12 4
A populateFromResponse() 0 11 3
B populateFromArray() 0 16 5
B parseDocBlockValue() 0 16 6
A isNotNativeType() 0 6 1
A normalizeModelClass() 0 9 2
A extractTypeFromDocBlock() 0 12 3
A getResourcesKey() 0 11 2
B enumerate() 0 27 3
A extractMultipleInstances() 0 15 3
A getService() 0 7 1
1
<?php
2
3
namespace OpenStack\Common\Resource;
4
5
use OpenStack\Common\Api\Operator;
6
use OpenStack\Common\Transport\Utils;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Represents a top-level abstraction of a remote API resource. Usually a resource represents a discrete
11
 * entity such as a Server, Container, Load Balancer. Apart from a representation of state, a resource can
12
 * also execute RESTFul operations on itself (updating, deleting, listing) or on other models.
13
 *
14
 * @package OpenStack\Common\Resource
15
 */
16
abstract class AbstractResource extends Operator implements ResourceInterface
17
{
18
    const DEFAULT_MARKER_KEY = 'id';
19
20
    /**
21
     * The JSON key that indicates how the API nests singular resources. For example, when
22
     * performing a GET, it could respond with ``{"server": {"id": "12345"}}``. In this case,
23
     * "server" is the resource key, since the essential state of the server is nested inside.
24
     *
25
     * @var string
26
     */
27
    protected $resourceKey;
28
29
    /**
30
     * The key that indicates how the API nests resource collections. For example, when
31
     * performing a GET, it could respond with ``{"servers": [{}, {}]}``. In this case, "servers"
32
     * is the resources key, since the array of servers is nested inside.
33
     *
34
     * @var string
35
     */
36
    protected $resourcesKey;
37
38
    /**
39
     * Indicates which attribute of the current resource should be used for pagination markers.
40
     *
41
     * @var string
42
     */
43
    protected $markerKey;
44
45
    /**
46
     * An array of aliases that will be checked when the resource is being populated. For example,
47
     *
48
     * 'FOO_BAR' => 'fooBar'
49
     *
50
     * will extract FOO_BAR from the response, and save it as 'fooBar' in the resource.
51
     *
52
     * @var array
53
     */
54
    protected $aliases = [];
55
56
    /**
57
     * Populates the current resource from a response object.
58
     *
59
     * @param ResponseInterface $response
60
     *
61
     * @return $this|ResourceInterface
62
     */
63 74
    public function populateFromResponse(ResponseInterface $response)
64
    {
65 74
        if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) {
66 61
            $json = Utils::jsonDecode($response);
67 61
            if (!empty($json)) {
68 61
                $this->populateFromArray(Utils::flattenJson($json, $this->resourceKey));
69 61
            }
70 61
        }
71
72 74
        return $this;
73
    }
74
75
    /**
76
     * Populates the current resource from a data array.
77
     *
78
     * @param array $array
79
     *
80
     * @return mixed|void
81
     */
82 133
    public function populateFromArray(array $array)
83
    {
84 133
        $reflClass = new \ReflectionClass($this);
85
86 133
        foreach ($array as $key => $val) {
87 133
            $propertyName = isset($this->aliases[$key]) ? $this->aliases[$key] : $key;
88
89 133
            if (property_exists($this, $propertyName)) {
90 131
                if ($type = $this->extractTypeFromDocBlock($reflClass, $propertyName)) {
91 128
                    $val = $this->parseDocBlockValue($type, $val);
92 128
                }
93
94 131
                $this->$propertyName = $val;
95 131
            }
96 133
        }
97 133
    }
98
99 128
    private function parseDocBlockValue($type, $val)
100 2
    {
101 128
        if (strpos($type, '[]') === 0 && is_array($val)) {
102 6
            $array = [];
103 6
            foreach ($val as $subVal) {
104 6
                $array[] = $this->model($this->normalizeModelClass(substr($type, 2)), $subVal);
105 6
            }
106 6
            $val = $array;
107 128
        } elseif (strcasecmp($type, '\datetimeimmutable') === 0) {
108 28
            $val = new \DateTimeImmutable($val);
109 127
        } elseif ($this->isNotNativeType($type)) {
110 11
            $val = $this->model($this->normalizeModelClass($type), $val);
111 11
        }
112
113 128
        return $val;
114
    }
115
116 124
    private function isNotNativeType($type)
117
    {
118 124
        return !in_array($type, [
119 124
            'string', 'bool', 'boolean', 'null', 'array', 'object', 'int', 'integer', 'float', 'numeric', 'mixed'
120 124
        ]);
121
    }
122
123 12
    private function normalizeModelClass($class)
124
    {
125 12
        if (strpos($class, '\\') === false) {
126 12
            $currentNamespace = (new \ReflectionClass($this))->getNamespaceName();
127 12
            $class = sprintf("%s\\%s", $currentNamespace, $class);
128 12
        }
129
130 12
        return $class;
131
    }
132
133 131
    private function extractTypeFromDocBlock(\ReflectionClass $reflClass, $propertyName)
134
    {
135 131
        $docComment = $reflClass->getProperty($propertyName)->getDocComment();
136
137 131
        if (!$docComment) {
138 3
            return false;
139
        }
140
141 128
        $matches = [];
142 128
        preg_match('#@var ((\[\])?[\w|\\\]+)#', $docComment, $matches);
143 128
        return isset($matches[1]) ? $matches[1] : null;
144
    }
145
146
    /**
147
     * Internal method which retrieves the values of provided keys.
148
     *
149
     * @param array $keys
150
     *
151
     * @return array
152
     */
153 65
    protected function getAttrs(array $keys)
154
    {
155 65
        $output = [];
156
157 65
        foreach ($keys as $key) {
158 65
            if (property_exists($this, $key) && $this->$key !== null) {
159 65
                $output[$key] = $this->$key;
160 65
            }
161 65
        }
162
163 65
        return $output;
164
    }
165
166
    /**
167
     * @param array $definition
168
     *
169
     * @return mixed
170
     */
171 60
    public function executeWithState(array $definition)
172
    {
173 60
        return $this->execute($definition, $this->getAttrs(array_keys($definition['params'])));
174
    }
175
176 38
    private function getResourcesKey()
177
    {
178 38
        $resourcesKey = $this->resourcesKey;
179
180 38
        if (!$resourcesKey) {
181 9
            $class = substr(static::class, strrpos(static::class, '\\') + 1);
182 9
            $resourcesKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class)) . 's';
183 9
        }
184
185 38
        return $resourcesKey;
186
    }
187
188
    /**
189
     * {@inheritDoc}
190
     */
191 33
    public function enumerate(array $def, array $userVals = [], callable $mapFn = null)
192
    {
193 33
        $operation = $this->getOperation($def);
194
195
        $requestFn = function ($marker) use ($operation, $userVals) {
196 33
            if ($marker) {
197 4
                $userVals['marker'] = $marker;
198 4
            }
199 33
            return $this->sendRequest($operation, $userVals);
200 33
        };
201
202 33
        $resourceFn = function (array $data) {
203 33
            $resource = $this->newInstance();
204 33
            $resource->populateFromArray($data);
205 33
            return $resource;
206 33
        };
207
208
        $opts = [
209 33
            'limit'        => isset($userVals['limit']) ? $userVals['limit'] : null,
210 33
            'resourcesKey' => $this->getResourcesKey(),
211 33
            'markerKey'    => $this->markerKey,
212 33
            'mapFn'        => $mapFn,
213 33
        ];
214
215 33
        $iterator = new Iterator($opts, $requestFn, $resourceFn);
216 33
        return $iterator();
217
    }
218
219 5
    public function extractMultipleInstances(ResponseInterface $response, $key = null)
220
    {
221 5
        $key = $key ?: $this->getResourcesKey();
222 5
        $resourcesData = Utils::jsonDecode($response)[$key];
223
224 5
        $resources = [];
225
226 5
        foreach ($resourcesData as $resourceData) {
227 5
            $resource = $this->newInstance();
228 5
            $resource->populateFromArray($resourceData);
229 5
            $resources[] = $resource;
230 5
        }
231
232 5
        return $resources;
233
    }
234
235 1
    protected function getService()
236
    {
237 1
        $class = static::class;
238 1
        $service = substr($class, 0, strpos($class, 'Models') - 1) . '\\Service';
239
240 1
        return new $service($this->client, $this->api);
241
    }
242
}
243