Completed
Push — master ( ea50c0...d3756e )
by Dmitry
06:23
created

QueryBuilder::buildNotInCondition()   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
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 2
1
<?php
2
3
/*
4
 * Tools to use API as ActiveRecord for Yii2
5
 *
6
 * @link      https://github.com/hiqdev/yii2-hiart
7
 * @package   yii2-hiart
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\hiart;
13
14
use yii\base\InvalidParamException;
15
use yii\base\NotSupportedException;
16
use yii\helpers\ArrayHelper;
17
18
/**
19
 * QueryBuilder builds an HiArt query based on the specification given as a [[Query]] object.
20
 */
21
class QueryBuilder extends \yii\base\Object
22
{
23
    private $_sort = [
24
        SORT_ASC  => '_asc',
25
        SORT_DESC => '_desc',
26
    ];
27
28
    public $db;
29
30
    public function __construct($connection, $config = [])
31
    {
32
        $this->db = $connection;
33
        parent::__construct($config);
34
    }
35
36
    /**
37
     * @param ActiveQuery $query
38
     *
39
     * @throws NotSupportedException
40
     *
41
     * @return array
42
     */
43
    public function build($query)
44
    {
45
        $parts = [];
46
        $query->prepare();
47
48
        $this->buildSelect($query->select, $parts);
49
        $this->buildLimit($query->limit, $parts);
50
        $this->buildPage($query->offset, $query->limit, $parts);
51
        $this->buildOrderBy($query->orderBy, $parts);
52
53
        $parts = ArrayHelper::merge($parts, $this->buildCondition($query->where));
54
55
        return [
56
            'queryParts' => $parts,
57
            'index'      => $query->index,
58
            'type'       => $query->type,
59
        ];
60
    }
61
62
    public function buildLimit($limit, &$parts)
63
    {
64
        if (!empty($limit)) {
65
            if ($limit === -1) {
66
                $limit = 'ALL';
67
            }
68
            $parts['limit'] = $limit;
69
        }
70
    }
71
72
    public function buildPage($offset, $limit, &$parts)
73
    {
74
        if ($offset > 0) {
75
            $parts['page'] = ceil($offset / $limit) + 1;
76
        }
77
    }
78
79
    public function buildOrderBy($orderBy, &$parts)
80
    {
81
        if (!empty($orderBy)) {
82
            $parts['orderby'] = key($orderBy) . $this->_sort[reset($orderBy)];
83
        }
84
    }
85
86
    public function buildSelect($select, &$parts)
87
    {
88
        if (!empty($select)) {
89
            foreach ($select as $attribute) {
90
                $parts['select'][$attribute] = $attribute;
91
            }
92
        }
93
    }
94
95
    public function buildCondition($condition)
96
    {
97
        static $builders = [
98
            'and'     => 'buildAndCondition',
99
            'between' => 'buildBetweenCondition',
100
            'eq'      => 'buildEqCondition',
101
            'ne'      => 'buildNotEqCondition',
102
            'in'      => 'buildInCondition',
103
            'ni'      => 'buildNotInCondition',
104
            'like'    => 'buildLikeCondition',
105
            'gt'      => 'buildCompareCondition',
106
            'ge'      => 'buildCompareCondition',
107
            'lt'      => 'buildCompareCondition',
108
            'le'      => 'buildCompareCondition',
109
        ];
110
        if (empty($condition)) {
111
            return [];
112
        }
113
        if (!is_array($condition)) {
114
            throw new NotSupportedException('String conditions in where() are not supported by HiArt.');
115
        }
116
117
        if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ...
118
            $operator = strtolower($condition[0]);
119
            if (isset($builders[$operator])) {
120
                $method = $builders[$operator];
121
                array_shift($condition); // Shift build condition
122
123
                return $this->$method($operator, $condition);
124
            } else {
125
                throw new InvalidParamException('Found unknown operator in query: ' . $operator);
126
            }
127
        } else {
128
            return $this->buildHashCondition($condition);
129
        }
130
    }
131
132
    private function buildHashCondition($condition)
133
    {
134
        $parts = [];
135
        foreach ($condition as $attribute => $value) {
136
            if (is_array($value)) { // IN condition
137
                // $parts[] = [$attribute.'s' => join(',',$value)];
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
138
                $parts[$attribute . 's'] = implode(',', $value);
139
            } else {
140
                $parts[$attribute] = $value;
141
            }
142
        }
143
144
        return $parts;
145
    }
146
147
    private function buildLikeCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
148
    {
149
        return [$operands[0] . '_like' => $operands[1]];
150
    }
151
152
    private function buildCompareCondition($operator, $operands)
153
    {
154
        if (!isset($operands[0], $operands[1])) {
155
            throw new InvalidParamException("Operator '$operator' requires three operands.");
156
        }
157
158
        return [$operands[0] . '_' . $operator => $operands[1]];
159
    }
160
161
    private function buildAndCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
162
    {
163
        $parts = [];
164
        foreach ($operands as $operand) {
165
            if (is_array($operand)) {
166
                $parts = \yii\helpers\ArrayHelper::merge($this->buildCondition($operand), $parts);
167
            }
168
        }
169
        if (!empty($parts)) {
170
            return $parts;
171
        } else {
172
            return [];
173
        }
174
    }
175
176
    private function buildBetweenCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operands is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
177
    {
178
        throw new NotSupportedException('Between condition is not supported by HiArt.');
179
    }
180
181
    private function buildInCondition($operator, $operands, $not = false)
182
    {
183
        if (!isset($operands[0], $operands[1])) {
184
            throw new InvalidParamException("Operator '$operator' requires two operands.");
185
        }
186
187
        list($column, $values) = $operands;
188
189
        if (count($column) > 1) {
190
            return $this->buildCompositeInCondition($operator, $column, $values);
191
        } elseif (is_array($column)) {
192
            $column = reset($column);
193
        }
194
195
        foreach ((array) $values as $i => $value) {
196
            if (is_array($value)) {
197
                $values[$i] = $value = isset($value[$column]) ? $value[$column] : null;
198
            }
199
            if ($value === null) {
200
                unset($values[$i]);
201
            }
202
        }
203
204
        if ($not) {
205
            $key = $column . '_ni'; // not in
206
        } else {
207
            $key = $column . '_in';
208
        }
209
        return [$key => $values];
210
    }
211
212
    private function buildNotInCondition($operator, $operands)
213
    {
214
        return $this->buildInCondition($operator, $operands, true);
215
    }
216
217
    private function buildEqCondition($operator, $operands)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
218
    {
219
        $key = array_shift($operands);
220
221
        return [$key => reset($operands)];
222
    }
223
224
    private function buildNotEqCondition($operator, $operands)
225
    {
226
        $key = array_shift($operands);
227
228
        return [$key . '_' . $operator => reset($operands)];
229
    }
230
231
    protected function buildCompositeInCondition($operator, $columns, $values)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $columns is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
232
    {
233
        throw new NotSupportedException('composite in is not supported by HiArt.');
234
    }
235
}
236