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.
Passed
Push — master ( 354c7c...907f89 )
by Jamie
05:42
created

Parameter::stockProperties()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
ccs 10
cts 10
cp 1
rs 9.2
cc 4
eloc 7
nc 4
nop 1
crap 4
1
<?php
2
3
namespace OpenStack\Common\Api;
4
5
use OpenStack\Common\HydratorStrategyTrait;
6
7
/**
8
 * Represents an individual request parameter in a RESTful operation. A parameter can take on many forms:
9
 * in a URL path, in a URL query, in a JSON body, and in a HTTP header. It is worth documenting brifly each
10
 * variety of parameter:
11
 *
12
 * * Header parameters are those which populate a HTTP header in a request. Header parameters can have
13
 *   aliases; for example, a user-facing name of "Foo" can be sent over the wire as "X-Foo_Bar", as defined
14
 *   by ``sentAs``. Prefixes can also be used.
15
 *
16
 * * Query parameters are those which populate a URL query parameter. The value is therefore usually
17
 *   confined to a string.
18
 *
19
 * * JSON parameters are those which populate a JSON request body. These are the most complex variety
20
 *   of Parameter, since there are so many different ways a JSON document can be constructed. The SDK
21
 *   supports deep-nesting according to a XPath syntax; for more information, see {@see \OpenStack\Common\JsonPath}.
22
 *   Nested object and array properties are also supported since JSON is a recursive data type. What
23
 *   this means is that a Parameter can have an assortment of child Parameters, one for each object
24
 *   property or array element.
25
 *
26
 * * Raw parameters are those which populate a non-JSON request body. This is typically used for
27
 *   uploading payloads (such as Swift object data) to a remote API.
28
 *
29
 * * Path parameters are those which populate a URL path. They are serialized according to URL
30
 *   placeholders.
31
 *
32
 * @package OpenStack\Common\Api
33
 */
34
class Parameter
35
{
36
    use HydratorStrategyTrait;
37
38
    const DEFAULT_LOCATION = 'json';
39
40
    /**
41
     * The human-friendly name of the parameter. This is what the user will input.
42
     *
43
     * @var string
44
     */
45
    private $name;
46
47
    /**
48
     * The alias for this parameter. Although the user will always interact with the human-friendly $name property,
49
     * the $sentAs is what's used over the wire.
50
     *
51
     * @var string
52
     */
53
    private $sentAs;
54
55
    /**
56
     * For array parameters (for example, an array of security group names when creating a server), each array element
57
     * will need to adhere to a common schema. For the aforementioned example, each element will need to be a string.
58
     * For more complicated parameters, you might be validated an array of complicated objects.
59
     *
60
     * @var Parameter
61
     */
62
    private $itemSchema;
63
64
    /**
65
     * For object parameters, each property will need to adhere to a specific schema. For every property in the
66
     * object, it has its own schema - meaning that this property is a hash of name/schema pairs.
67
     *
68
     * The *only* exception to this rule is for metadata parameters, which are arbitrary key/value pairs. Since it does
69
     * not make sense to have a schema for each metadata key, a common schema is use for every one. So instead of this
70
     * property being a hash of schemas, it is a single Parameter object instead. This single Parameter schema will
71
     * then be applied to each metadata key provided.
72
     *
73
     * @var []Parameter|Parameter
74
     */
75
    private $properties;
76
77
    /**
78
     * The value's PHP type which this parameter represents; either "string", "bool", "object", "array", "NULL".
79
     *
80
     * @var string
81
     */
82
    private $type;
83
84
    /**
85
     * Indicates whether this parameter requires a value from the user.
86
     *
87
     * @var bool
88
     */
89
    private $required;
90
91
    /**
92
     * The location in the HTTP request where this parameter will populate; either "header", "url", "query", "raw" or
93
     * "json".
94
     *
95
     * @var string
96
     */
97
    private $location;
98
99
    /**
100
     * Relevant to "json" location parameters only. This property allows for deep nesting through the use of
101
     * {@see OpenStack\Common\JsonPath}.
102
     *
103
     * @var string
104
     */
105
    private $path;
106
107
    /**
108
     * Allows for the prefixing of parameter names.
109
     *
110
     * @var string
111
     */
112
    private $prefix;
113
114
    /**
115
     * The enum values for which this param is restricted.
116
     *
117
     * @var array
118
     */
119
    private $enum;
120
121
    /**
122
     * @param array $data
123
     */
124 211
    public function __construct(array $data)
125
    {
126 211
        $this->hydrate($data);
127
128 211
        if (!$this->type) {
129 98
            $this->type = 'string';
130 98
        }
131
132 211
        $this->required = (bool)$this->required;
133
134 211
        $this->stockLocation($data);
135 211
        $this->stockItemSchema($data);
136 211
        $this->stockProperties($data);
137 211
    }
138
139 211
    private function stockLocation(array $data)
140
    {
141 211
        $this->location = isset($data['location']) ? $data['location'] : self::DEFAULT_LOCATION;
142
143 211
        if (!AbstractParams::isSupportedLocation($this->location)) {
144 1
            throw new \RuntimeException(sprintf("%s is not a permitted location", $this->location));
145
        }
146 211
    }
147
148 211
    private function stockItemSchema(array $data)
149
    {
150 211
        if (isset($data['items'])) {
151 26
            $this->itemSchema = new Parameter($data['items']);
152 26
        }
153 211
    }
154
155 211
    private function stockProperties(array $data)
156
    {
157 211
        if (isset($data['properties'])) {
158 39
            if (strpos(strtolower($this->name), 'metadata') !== false) {
159 22
                $this->properties = new Parameter($data['properties']);
160 22
            } else {
161 27
                foreach ($data['properties'] as $name => $property) {
162 27
                    $this->properties[$name] = new Parameter($property + ['name' => $name]);
163 27
                }
164
            }
165 39
        }
166 211
    }
167
168
    /**
169
     * Retrieve the name that will be used over the wire.
170
     *
171
     * @return string
172
     */
173 93
    public function getName()
174
    {
175 93
        return $this->sentAs ?: $this->name;
176
    }
177
178
    /**
179
     * Indicates whether the user must provide a value for this parameter.
180
     *
181
     * @return bool
182
     */
183 55
    public function isRequired()
184
    {
185 55
        return $this->required === true;
186
    }
187
188
    /**
189
     * Validates a given user value and checks whether it passes basic sanity checking, such as types.
190
     *
191
     * @param $userValues The value provided by the user
192
     *
193
     * @return bool       TRUE if the validation passes
194
     * @throws \Exception If validation fails
195
     */
196 187
    public function validate($userValues)
197
    {
198 187
        $this->validateEnums($userValues);
199 186
        $this->validateType($userValues);
200
201 185
        if ($this->isArray()) {
202 12
            $this->validateArray($userValues);
203 184
        } elseif ($this->isObject()) {
204 22
            $this->validateObject($userValues);
205 21
        }
206
207 183
        return true;
208
    }
209
210 187
    private function validateEnums($userValues)
211
    {
212 187
        if (!empty($this->enum) && $this->type == 'string' && !in_array($userValues, $this->enum)) {
213 1
            throw new \Exception(sprintf(
214 1
                'The only permitted values are %s. You provided %s', implode(', ', $this->enum), $userValues
215 1
            ));
216
        }
217 186
    }
218
219 186
    private function validateType($userValues)
220
    {
221 186
        if (!$this->hasCorrectType($userValues)) {
222 3
            throw new \Exception(sprintf(
223 3
                'The key provided "%s" has the wrong value type. You provided %s but was expecting %s',
224 3
                $this->name, print_r($userValues, true), $this->type
225 3
            ));
226
        }
227 185
    }
228
229 12
    private function validateArray($userValues)
230
    {
231 12
        foreach ($userValues as $userValue) {
232 12
            $this->itemSchema->validate($userValue);
233 11
        }
234 11
    }
235
236 22
    private function validateObject($userValues)
237
    {
238 22
        foreach ($userValues as $key => $userValue) {
239 22
            $property = $this->getNestedProperty($key);
240 21
            $property->validate($userValue);
241 21
        }
242 21
    }
243
244
    /**
245
     * Internal method which retrieves a nested property for object parameters.
246
     *
247
     * @param $key The name of the child parameter
248
     *
249
     * @returns Parameter
250
     * @throws \Exception
251
     */
252 22
    private function getNestedProperty($key)
253
    {
254 22
        if ($this->name == 'metadata' && $this->properties instanceof Parameter) {
255 12
            return $this->properties;
256 11
        } elseif (isset($this->properties[$key])) {
257 10
            return $this->properties[$key];
258
        } else {
259 1
            throw new \Exception(sprintf('The key provided "%s" is not defined', $key));
260
        }
261
    }
262
263
    /**
264
     * Internal method which indicates whether the user value is of the same type as the one expected
265
     * by this parameter.
266
     *
267
     * @param $userValue The value being checked
268
     *
269
     * @return bool
270
     */
271
    private function hasCorrectType($userValue)
272
    {
273
        // Helper fn to see whether an array is associative (i.e. a JSON object)
274 186
        $isAssociative = function ($value) {
275 31
            return is_array($value) && (bool)count(array_filter(array_keys($value), 'is_string'));
276 186
        };
277
278
        // For params defined as objects, we'll let the user get away with
279
        // passing in an associative array - since it's effectively a hash
280 186
        if ($this->type == 'object' && $isAssociative($userValue)) {
281 30
            return true;
282
        }
283
284 183
        if (class_exists($this->type) || interface_exists($this->type)) {
285 1
            return is_a($userValue, $this->type);
286
        }
287
288 183
        return gettype($userValue) == $this->type;
289
    }
290
291
    /**
292
     * Indicates whether this parameter represents an array type
293
     *
294
     * @return bool
295
     */
296 185
    public function isArray()
297
    {
298 185
        return $this->type == 'array' && $this->itemSchema instanceof Parameter;
299
    }
300
301
    /**
302
     * Indicates whether this parameter represents an object type
303
     *
304
     * @return bool
305
     */
306 184
    public function isObject()
307
    {
308 184
        return $this->type == 'object' && !empty($this->properties);
309
    }
310
311 177
    public function getLocation()
312
    {
313 177
        return $this->location;
314
    }
315
316
    /**
317
     * Verifies whether the given location matches the parameter's location.
318
     *
319
     * @param $value
320
     *
321
     * @return bool
322
     */
323 1
    public function hasLocation($value)
324
    {
325 1
        return $this->location == $value;
326
    }
327
328
    /**
329
     * Retrieves the parameter's path.
330
     *
331
     * @return string|null
332
     */
333 65
    public function getPath()
334
    {
335 65
        return $this->path;
336
    }
337
338
    /**
339
     * Retrieves the common schema that an array parameter applies to all its child elements.
340
     *
341
     * @return Parameter
342
     */
343 19
    public function getItemSchema()
344
    {
345 19
        return $this->itemSchema;
346
    }
347
348
    /**
349
     * Sets the name of the parameter to a new value
350
     *
351
     * @param string $name
352
     */
353 13
    public function setName($name)
354
    {
355 13
        $this->name = $name;
356 13
    }
357
358
    /**
359
     * Retrieves the child parameter for an object parameter.
360
     *
361
     * @param string $name The name of the child property
362
     *
363
     * @return null|Parameter
364
     */
365 21
    public function getProperty($name)
366
    {
367 21
        if ($this->properties instanceof Parameter) {
368 12
            $this->properties->setName($name);
369 12
            return $this->properties;
370
        }
371
372 10
        return isset($this->properties[$name]) ? $this->properties[$name] : null;
373
    }
374
375
    /**
376
     * Retrieves the prefix for a parameter, if any.
377
     *
378
     * @return string|null
379
     */
380 9
    public function getPrefix()
381
    {
382 9
        return $this->prefix;
383
    }
384
385 15
    public function getPrefixedName()
386
    {
387 15
        return $this->prefix . $this->getName();
388
    }
389
}