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 ( 658651...354c7c )
by Jamie
07:31
created

Parameter::isRequired()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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
     * @param array $data
116
     */
117 194
    public function __construct(array $data)
118
    {
119 194
        $this->hydrate($data);
120
121 194
        if (!$this->type) {
122 98
            $this->type = 'string';
123 98
        }
124
125 194
        $this->required = (bool)$this->required;
126
127 194
        $this->stockLocation($data);
128 194
        $this->stockItemSchema($data);
129 194
        $this->stockProperties($data);
130 194
    }
131
132 194
    private function stockLocation(array $data)
133
    {
134 194
        $this->location = isset($data['location']) ? $data['location'] : self::DEFAULT_LOCATION;
135
136 194
        if (!AbstractParams::isSupportedLocation($this->location)) {
137
            throw new \RuntimeException(sprintf("%s is not a permitted location", $this->location));
138
        }
139 194
    }
140
141 194
    private function stockItemSchema(array $data)
142
    {
143 194
        if (isset($data['items'])) {
144 25
            $this->itemSchema = new Parameter($data['items']);
145 25
        }
146 194
    }
147
148 194
    private function stockProperties(array $data)
149
    {
150 194
        if (isset($data['properties'])) {
151 39
            if (strpos(strtolower($this->name), 'metadata') !== false) {
152 22
                $this->properties = new Parameter($data['properties']);
153 22
            } else {
154 27
                foreach ($data['properties'] as $name => $property) {
155 27
                    $this->properties[$name] = new Parameter($property + ['name' => $name]);
156 27
                }
157
            }
158 39
        }
159 194
    }
160
161
    /**
162
     * Retrieve the name that will be used over the wire.
163
     *
164
     * @return string
165
     */
166 87
    public function getName()
167
    {
168 87
        return $this->sentAs ?: $this->name;
169
    }
170
171
    /**
172
     * Indicates whether the user must provide a value for this parameter.
173
     *
174
     * @return bool
175
     */
176 54
    public function isRequired()
177
    {
178 54
        return $this->required === true;
179
    }
180
181
    /**
182
     * Validates a given user value and checks whether it passes basic sanity checking, such as types.
183
     *
184
     * @param $userValues The value provided by the user
185
     *
186
     * @return bool       TRUE if the validation passes
187
     * @throws \Exception If validation fails
188
     */
189 171
    public function validate($userValues)
190
    {
191 171
        $this->validateType($userValues);
192
193 170
        if ($this->isArray()) {
194 11
            $this->validateArray($userValues);
195 169
        } elseif ($this->isObject()) {
196 22
            $this->validateObject($userValues);
197 21
        }
198
199 168
        return true;
200
    }
201
202 171
    private function validateType($userValues)
203
    {
204 171
        if (!$this->hasCorrectType($userValues)) {
205 3
            throw new \Exception(sprintf(
206 3
                'The key provided "%s" has the wrong value type. You provided %s but was expecting %s',
207 3
                $this->name, print_r($userValues, true), $this->type
208 3
            ));
209
        }
210 170
    }
211
212 11
    private function validateArray($userValues)
213
    {
214 11
        foreach ($userValues as $userValue) {
215 11
            $this->itemSchema->validate($userValue);
216 10
        }
217 10
    }
218
219 22
    private function validateObject($userValues)
220
    {
221 22
        foreach ($userValues as $key => $userValue) {
222 22
            $property = $this->getNestedProperty($key);
223 21
            $property->validate($userValue);
224 21
        }
225 21
    }
226
227
    /**
228
     * Internal method which retrieves a nested property for object parameters.
229
     *
230
     * @param $key The name of the child parameter
231
     *
232
     * @returns Parameter
233
     * @throws \Exception
234
     */
235 22
    private function getNestedProperty($key)
236
    {
237 22
        if ($this->name == 'metadata' && $this->properties instanceof Parameter) {
238 12
            return $this->properties;
239 11
        } elseif (isset($this->properties[$key])) {
240 10
            return $this->properties[$key];
241
        } else {
242 1
            throw new \Exception(sprintf('The key provided "%s" is not defined', $key));
243
        }
244
    }
245
246
    /**
247
     * Internal method which indicates whether the user value is of the same type as the one expected
248
     * by this parameter.
249
     *
250
     * @param $userValue The value being checked
251
     *
252
     * @return bool
253
     */
254
    private function hasCorrectType($userValue)
255
    {
256
        // Helper fn to see whether an array is associative (i.e. a JSON object)
257 171
        $isAssociative = function ($value) {
258 31
            return is_array($value) && (bool)count(array_filter(array_keys($value), 'is_string'));
259 171
        };
260
261
        // For params defined as objects, we'll let the user get away with
262
        // passing in an associative array - since it's effectively a hash
263 171
        if ($this->type == 'object' && $isAssociative($userValue)) {
264 30
            return true;
265
        }
266
267 168
        return gettype($userValue) == $this->type;
268
    }
269
270
    /**
271
     * Indicates whether this parameter represents an array type
272
     *
273
     * @return bool
274
     */
275 170
    public function isArray()
276
    {
277 170
        return $this->type == 'array' && $this->itemSchema instanceof Parameter;
278
    }
279
280
    /**
281
     * Indicates whether this parameter represents an object type
282
     *
283
     * @return bool
284
     */
285 169
    public function isObject()
286
    {
287 169
        return $this->type == 'object' && !empty($this->properties);
288
    }
289
290 162
    public function getLocation()
291
    {
292 162
        return $this->location;
293
    }
294
295
    /**
296
     * Verifies whether the given location matches the parameter's location.
297
     *
298
     * @param $value
299
     *
300
     * @return bool
301
     */
302 1
    public function hasLocation($value)
303
    {
304 1
        return $this->location == $value;
305
    }
306
307
    /**
308
     * Retrieves the parameter's path.
309
     *
310
     * @return string|null
311
     */
312 62
    public function getPath()
313
    {
314 62
        return $this->path;
315
    }
316
317
    /**
318
     * Retrieves the common schema that an array parameter applies to all its child elements.
319
     *
320
     * @return Parameter
321
     */
322 18
    public function getItemSchema()
323
    {
324 18
        return $this->itemSchema;
325
    }
326
327
    /**
328
     * Sets the name of the parameter to a new value
329
     *
330
     * @param string $name
331
     */
332 13
    public function setName($name)
333
    {
334 13
        $this->name = $name;
335 13
    }
336
337
    /**
338
     * Retrieves the child parameter for an object parameter.
339
     *
340
     * @param string $name The name of the child property
341
     *
342
     * @return null|Parameter
343
     */
344 21
    public function getProperty($name)
345
    {
346 21
        if ($this->properties instanceof Parameter) {
347 12
            $this->properties->setName($name);
348 12
            return $this->properties;
349
        }
350
351 10
        return isset($this->properties[$name]) ? $this->properties[$name] : null;
352
    }
353
354
    /**
355
     * Retrieves the prefix for a parameter, if any.
356
     *
357
     * @return string|null
358
     */
359 9
    public function getPrefix()
360
    {
361 9
        return $this->prefix;
362
    }
363
364 13
    public function getPrefixedName()
365
    {
366 13
        return $this->prefix . $this->getName();
367
    }
368
}