Completed
Push — master ( 0168ae...d7f082 )
by ignace nyamagana
02:54
created

Query::createFromArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * League.Uri (http://uri.thephpleague.com)
4
 *
5
 * @package   League.uri
6
 * @author    Ignace Nyamagana Butera <[email protected]>
7
 * @copyright 2013-2015 Ignace Nyamagana Butera
8
 * @license   https://github.com/thephpleague/uri/blob/master/LICENSE (MIT License)
9
 * @version   4.1.0
10
 * @link      https://github.com/thephpleague/uri/
11
 */
12
namespace League\Uri\Components;
13
14
use InvalidArgumentException;
15
use League\Uri\Interfaces\Query as QueryInterface;
16
use League\Uri\QueryParser;
17
use League\Uri\Types\ImmutableCollectionTrait;
18
use League\Uri\Types\ImmutableComponentTrait;
19
20
/**
21
 * Value object representing a URI query component.
22
 *
23
 * @package League.uri
24
 * @author  Ignace Nyamagana Butera <[email protected]>
25
 * @since   1.0.0
26
 */
27
class Query implements QueryInterface
28
{
29
    use ImmutableComponentTrait;
30
31
    use ImmutableCollectionTrait;
32
33
    /**
34
     * Key/pair separator character
35
     *
36
     * @var string
37
     */
38
    protected static $separator = '&';
39
40
    /**
41
     * Preserve the delimiter
42
     *
43
     * @var bool
44
     */
45
    protected $preserveDelimiter = false;
46
47
    /**
48
     * DEPRECATION WARNING! This method will be removed in the next major point release
49
     *
50
     * @deprecated deprecated since version 4.2
51
     *
52
     * return a new instance from an array or a traversable object
53
     *
54
     * @param \Traversable|array $data
55
     *
56
     * @return static
57
     */
58
    public static function createFromArray($data)
59
    {
60
        return self::createFromPairs($data);
61
    }
62
63
    /**
64
     * return a new Query instance from an Array or a traversable object
65
     *
66
     * @param \Traversable|array $data
67
     *
68
     * @return static
69
     */
70 108
    public static function createFromPairs($data)
71
    {
72 108
        $data = static::validateIterator($data);
73 102
        if (empty($data)) {
74 27
            return new static();
75
        }
76
77 81
        $query = (new QueryParser())->build($data, static::$separator);
78
79 81
        return new static($query);
80
    }
81
82
    /**
83
     * a new instance
84
     *
85
     * @param string $data
86
     */
87 979
    public function __construct($data = null)
88
    {
89 979
        $this->data = $this->validate($data);
90 979
        $this->preserveDelimiter = null !== $data;
91 979
    }
92
93
    /**
94
     * sanitize the submitted data
95
     *
96
     * @param string $str
97
     *
98
     * @return array
99
     */
100 979
    protected function validate($str)
101
    {
102 979
        if (null === $str) {
103 474
            return [];
104
        }
105
106 766
        $str = $this->filterEncodedQuery($this->validateString($str));
107
108 766
        return (new QueryParser())->parse($str, static::$separator, PHP_QUERY_RFC3986);
109
    }
110
111
    /**
112
     * Filter the encoded query string
113
     *
114
     * @param string $str the encoded query
115
     *
116
     * @throws InvalidArgumentException If the encoded query is invalid
117
     *
118
     * @return string
119
     */
120 766
    protected function filterEncodedQuery($str)
121
    {
122 766
        if (false === strpos($str, '#')) {
123 766
            return $str;
124
        }
125
126 3
        throw new InvalidArgumentException(sprintf(
127 3
            'The encoded query `%s` contains invalid characters',
128
            $str
129 2
        ));
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135 2
    public function __debugInfo()
136
    {
137 2
        return ['query' => $this->getContent()];
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143 12
    public static function __set_state(array $properties)
144
    {
145 12
        $component = static::createFromPairs($properties['data']);
146 12
        $component->preserveDelimiter = $properties['preserveDelimiter'];
147
148 12
        return $component;
149
    }
150
151
    /**
152
     * Returns the component literal value.
153
     *
154
     * @return null|string
155
     */
156 889
    public function getContent()
157
    {
158 889
        if (!$this->preserveDelimiter) {
159 501
            return null;
160
        }
161
162 673
        return (new QueryParser())->build($this->data, static::$separator, PHP_QUERY_RFC3986);
163
    }
164
165
    /**
166
     * Returns the instance string representation; If the
167
     * instance is not defined an empty string is returned
168
     *
169
     * @return string
170
     */
171 883
    public function __toString()
172
    {
173 883
        return (string) $this->getContent();
174
    }
175
176
    /**
177
     * Returns the instance string representation
178
     * with its optional URI delimiters
179
     *
180
     * @return string
181
     */
182 833
    public function getUriComponent()
183
    {
184 833
        $query = $this->__toString();
185 833
        if ($this->preserveDelimiter) {
186 599
            return QueryInterface::DELIMITER.$query;
187
        }
188
189 483
        return $query;
190
    }
191
192
    /**
193
     * DEPRECATION WARNING! This method will be removed in the next major point release
194
     *
195
     * @deprecated deprecated since version 4.2
196
     *
197
     * Returns an array representation of the query
198
     *
199
     * @return array
200
     */
201
    public function toArray()
202
    {
203
        return $this->getPairs();
204
    }
205
206
    /**
207
     * Returns an array representation of the query
208
     *
209
     * @return array
210
     */
211 54
    public function getPairs()
212
    {
213 54
        return $this->data;
214
    }
215
216
    /**
217
     * Retrieves a single query parameter.
218
     *
219
     * Retrieves a single query parameter. If the parameter has not been set,
220
     * returns the default value provided.
221
     *
222
     * @param string $offset  the parameter name
223
     * @param mixed  $default Default value to return if the parameter does not exist.
224
     *
225
     * @return mixed
226
     */
227 9
    public function getValue($offset, $default = null)
228
    {
229 9
        $offset = $this->validateString($offset);
230 9
        $offset = $this->decodeComponent($offset);
231 9
        if (isset($this->data[$offset])) {
232 3
            return $this->data[$offset];
233
        }
234
235 6
        return $default;
236
    }
237
238
    /**
239
     * Returns an instance with the specified string
240
     *
241
     * This method MUST retain the state of the current instance, and return
242
     * an instance that contains the modified data
243
     *
244
     * @param string $value
245
     *
246
     * @return static
247
     */
248 240
    public function withContent($value = null)
249
    {
250 240
        if ($value === $this->getContent()) {
251 207
            return $this;
252
        }
253
254 33
        return new static($value);
255
    }
256
257
    /**
258
     * DEPRECATION WARNING! This method will be removed in the next major point release
259
     *
260
     * @deprecated deprecated since version 4.2
261
     *
262
     * @see withContent
263
     *
264
     * Returns an instance with the specified string
265
     *
266
     * This method MUST retain the state of the current instance, and return
267
     * an instance that contains the modified data
268
     *
269
     * @param string $value
270
     *
271
     * @return static
272
     */
273
    public function modify($value)
274
    {
275
        return $this->withContent($value);
276
    }
277
278
    /**
279
     * Returns an instance merge with the specified query
280
     *
281
     * This method MUST retain the state of the current instance, and return
282
     * an instance that contains the modified query
283
     *
284
     * @param QueryInterface|string $query the data to be merged
285
     *
286
     * @return static
287
     */
288 24
    public function merge($query)
289
    {
290 24
        $pairs = !$query instanceof QueryInterface ? $this->validate($query) : $query->getPairs();
291 24
        if ($this->data === $pairs) {
292 3
            return $this;
293
        }
294
295 21
        return static::createFromPairs(array_merge($this->data, $pairs));
296
    }
297
298
    /**
299
     * Sort the query string by offset, maintaining offset to data correlations.
300
     *
301
     * This method MUST retain the state of the current instance, and return
302
     * an instance that contains the modified query
303
     *
304
     * @param callable|int $sort a PHP sort flag constant or a comparaison function
305
     *                           which must return an integer less than, equal to,
306
     *                           or greater than zero if the first argument is
307
     *                           considered to be respectively less than, equal to,
308
     *                           or greater than the second.
309
     *
310
     * @return static
311
     */
312 57
    public function ksort($sort = SORT_REGULAR)
313
    {
314 57
        $func = is_callable($sort) ? 'uksort' : 'ksort';
315 57
        $data = $this->data;
316 57
        $func($data, $sort);
317 57
        if ($data === $this->data) {
318 45
            return $this;
319
        }
320
321 12
        return static::createFromPairs($data);
322
    }
323
324
    /**
325
     * @inheritdoc
326
     */
327 3
    public function hasKey($offset)
328
    {
329 3
        $offset = $this->validateString($offset);
330 3
        $offset = $this->decodeComponent($offset);
331
332 3
        return array_key_exists($offset, $this->data);
333
    }
334
335
    /**
336
     * @inheritdoc
337
     */
338 6
    public function keys()
339
    {
340 6
        if (0 === func_num_args()) {
341 3
            return array_keys($this->data);
342
        }
343
344 3
        return array_keys($this->data, $this->decodeComponent(func_get_arg(0)), true);
345
    }
346
347
    /**
348
     * @inheritdoc
349
     */
350 9
    public function without(array $offsets)
351
    {
352 9
        $data = $this->data;
353 9
        foreach ($offsets as $offset) {
354 9
            unset($data[$this->decodeComponent($offset)]);
355 6
        }
356
357 9
        return $this->newCollectionInstance($data);
358
    }
359
360
361
362
    /**
363
     * Return a new instance when needed
364
     *
365
     * @param array $data
366
     *
367
     * @return static
368
     */
369 42
    protected function newCollectionInstance(array $data)
370
    {
371 42
        if ($data === $this->data) {
372 15
            return $this;
373
        }
374
375 27
        return static::createFromPairs($data);
376
    }
377
}
378