QueryFilterTrait::operatorExpression()   D
last analyzed

Complexity

Conditions 20
Paths 20

Size

Total Lines 48
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 37
nc 20
nop 4
dl 0
loc 48
rs 4.1666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2018 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\Core\ORM;
15
16
use Cake\Database\Expression\Comparison;
17
use Cake\Database\Expression\QueryExpression;
18
use Cake\ORM\Query;
19
20
/**
21
 * Query Filter trait.
22
 *
23
 * @since 4.0.0
24
 */
25
trait QueryFilterTrait
26
{
27
    /**
28
     * Create query filter using various operators on fields
29
     * Options array must contain fields as keys and operators like
30
     *   - 'gt' or '>' (greather than)
31
     *   - 'lt' or '<' (less than),
32
     *   - 'ge' or '>=' (greater or equal)
33
     *   - 'le' or '<=' (less or equal) with a date
34
     *
35
     * It's also possible to specify an expected value or a list of values for a field
36
     *
37
     * Options array examples:
38
     *
39
     * ```
40
     * // field1 greater than 10, field2 less then 5
41
     * ['field1' => ['gt' => 10], 'field2' => ['lt' => 5]];
42
     *
43
     * // field1 in [1, 3, 10]
44
     * ['field1' => [1, 3, 10]];
45
     *
46
     * // a comma separated string has the same effect as a list of values
47
     * ['field1' => '1,3,10'];
48
     *
49
     * // field1 equals 10, field2 equals 1
50
     * ['field1' => 10, 'field1' => ['eq' => 1]];
51
     *
52
     * // field1 greater or equal 5, field2 less or equal 4
53
     * ['field1' => ['>=' => 10], 'field2' => ['<=' => 4]];
54
     *
55
     * // field1 is null, field2 is not null, field3 is null
56
     * ['field1' => ['null' => 1], 'field2' => ['null' => 0], 'field3' => null];
57
     * ```
58
     *
59
     * //
60
61
     * @param \Cake\ORM\Query $query Query object instance.
62
     * @param array $options Array of acceptable fields and conditions.
63
     * @return \Cake\ORM\Query
64
     */
65
    public function fieldsFilter(Query $query, array $options)
66
    {
67
        return $query->where(function (QueryExpression $exp) use ($options) {
68
            foreach ($options as $field => $conditions) {
69
                if ($conditions === null) {
70
                    $exp = $exp->isNull($field);
71
72
                    continue;
73
                }
74
75
                if (!is_array($conditions)) {
76
                    if (is_string($conditions) && strpos($conditions, ',') !== false) {
77
                        $conditions = explode(',', $conditions);
78
                    } else {
79
                        $exp = $exp->eq($field, $conditions);
80
81
                        continue;
82
                    }
83
                }
84
85
                $in = [];
86
                foreach ($conditions as $operator => $value) {
87
                    if (is_numeric($operator)) {
88
                        $in[] = $value;
89
                        continue;
90
                    }
91
                    $exp = $this->operatorExpression($exp, $operator, $field, $value);
92
                }
93
                if (!empty($in)) {
94
                    $exp = $exp->in($field, $in);
95
                }
96
            }
97
98
            // return the current expression if not empty
99
            // otherwise a trivial comparison to avoid SQL errors
100
            return $exp->count() > 0 ? $exp : new Comparison('1', '1', 'integer', '=');
101
        });
102
    }
103
104
    /**
105
     * Get query expression for an operator on a field with a value.
106
     * Unrecognized operators are ignored and have no effect.
107
     *
108
     * @param \Cake\Database\Expression\QueryExpression $exp Current query expression
109
     * @param string $operator Filter operator
110
     * @param string $field Filter field
111
     * @param string $value Filter value
112
     * @return \Cake\Database\Expression\QueryExpression Operator query expression
113
     */
114
    protected function operatorExpression(QueryExpression $exp, $operator, $field, $value)
115
    {
116
        switch ($operator) {
117
            case 'eq':
118
            case '=':
119
                $exp = $exp->eq($field, $value);
120
                break;
121
122
            case 'neq':
123
            case 'ne':
124
            case '!=':
125
            case '<>':
126
                $exp = $exp->notEq($field, $value);
127
                break;
128
129
            case 'lt':
130
            case '<':
131
                $exp = $exp->lt($field, $value);
132
                break;
133
134
            case 'lte':
135
            case 'le':
136
            case '<=':
137
                $exp = $exp->lte($field, $value);
138
                break;
139
140
            case 'gt':
141
            case '>':
142
                $exp = $exp->gt($field, $value);
143
                break;
144
145
            case 'gte':
146
            case 'ge':
147
            case '>=':
148
                $exp = $exp->gte($field, $value);
149
                break;
150
151
            case 'null':
152
                $op = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
153
                if ($op === false) {
154
                    $exp = $exp->isNotNull($field);
155
                } elseif ($op === true) {
156
                    $exp = $exp->isNull($field);
157
                }
158
                break;
159
        }
160
161
        return $exp;
162
    }
163
}
164