Completed
Pull Request — master (#30)
by Phil
15:25
created

QueryStringParserTrait::parseSort()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 21
ccs 13
cts 13
cp 1
rs 9.0534
cc 4
eloc 12
nc 5
nop 1
crap 4
1
<?php
2
3
namespace Percy\Http;
4
5
use InvalidArgumentException;
6
7
trait QueryStringParserTrait
8
{
9
    /**
10
     * Parse HTTP query string and return array representation
11
     * to be attached to a database query.
12
     *
13
     * @param string $query
14
     *
15
     * @return array
16
     */
17 11
    public function parseQueryString($query)
18
    {
19 11
        if (empty($query)) {
20 1
            return [];
21
        }
22
23 10
        parse_str($query, $split);
24
25
        $query = [];
26 10
27 10
        while (list($key, $value) = each($split)) {
28
            $mapped = call_user_func_array([$this, 'filterQueryParams'], [$key, $value]);
29 10
            if ($mapped !== false) {
30 10
                $query[$key] = $mapped;
31 8
            }
32 7
        }
33 7
34 8
        return $query;
35
    }
36 8
37
    /**
38
     * Map the parsed query string in to correct array structure.
39
     *
40
     * @param string $key
41
     * @param mixed  $value
42
     *
43
     * @return array|boolean
44
     */
45
    protected function filterQueryParams($key, $value)
46
    {
47 10
        switch ($key) {
48
            case 'limit':
49
            case 'offset':
50 10
                return (int) $value;
51 10
            case 'sort':
52 1
                return $this->parseSort($value);
53 10
            case 'filter':
54 1
                return $this->parseFilters((array) $value);
55 10
            case 'search':
56 7
                return $this->parseSearch($value);
57 10
            case 'minscore':
58 9
                return (float) $value;
59 1
            default:
60 1
                return false;
61 1
        }
62
    }
63
64
    /**
65
     * Map sorts to a usable format.
66
     *
67
     * @param string $value
68
     *
69
     * @return array
70
     */
71 9
    protected function parseSort($value)
72
    {
73 9
        $map   = [];
74 9
        $sorts = explode(',', $value);
75
76 9
        foreach ($sorts as $sort) {
77 9
            $sort      = explode('|', $sort);
78
            $direction = (count($sort) > 1) ? $sort[1] : 'asc';
79 9
80 1
            if (in_array($sort[0], ['rand', 'random'])) {
81
                return 'RAND()';
82 1
            }
83
84
            $map[] = [
85 8
                'field'     => $sort[0],
86
                'direction' => $direction
87 8
            ];
88 8
        }
89 8
90
        return $map;
91 8
    }
92 8
93 8
    /**
94 1
     * Map search to a usable format.
95
     *
96
     * @param string $value
97 7
     *
98 7
     * @return array
99
     */
100 7
    protected function parseSearch($value)
101
    {
102
        $search = explode('|', $value);
103
104
        if (count($search) !== 2) {
105
            throw new InvalidArgumentException(
106
                'Malformed query string, search format should be (search=field|term) or (search=field1,field2|term)'
107
            );
108
        }
109
110
        return [
111
            'fields' => $search[0],
112
            'term'   => $search[1]
113
        ];
114
    }
115
116
    /**
117
     * Map filters in to useable array.
118
     *
119
     * @param array $filters
120
     *
121
     * @return array
122
     */
123
    protected function parseFilters(array $filters)
124
    {
125
        $mapped = [];
126
        $param  = 0;
127
128
        foreach ($filters as $filter) {
129
            $filter = explode('|', $filter);
130
131
            if (count($filter) !== 3) {
132
                throw new InvalidArgumentException(
133
                    'Malformed query string, filter format should be (filter[]=field|delimiter|value)'
134
                );
135
            }
136
137
            $filter = array_combine(['field', 'delimiter', 'value'], $filter);
138
139
            $filter['binding']   = str_replace('.', '_', $filter['field']) . '_' . $param++;
140
            $filter['delimiter'] = strtolower($filter['delimiter']);
141
            $filter['delimiter'] = html_entity_decode($filter['delimiter']);
142
143
            if (! in_array($filter['delimiter'], [
144
                '=', '!=', '<>', '<=', '>=', '<', '>', 'in', 'not in', 'like', 'not like'
145
            ])) {
146
                throw new InvalidArgumentException(sprintf('(%s) is not an accepted delimiter', $filter['delimiter']));
147
            }
148
149
            $mapped[] = $filter;
150
        }
151
152
        return $mapped;
153
    }
154
}
155