Completed
Push — master ( 26679d...412cec )
by Andrii
12:10
created

QueryBuilder::buildPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 6
ccs 0
cts 6
cp 0
rs 9.4285
cc 2
eloc 3
nc 2
nop 3
crap 6
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
            'in'      => 'buildInCondition',
102
            'like'    => 'buildLikeCondition',
103
            'gt'      => 'buildCompareCondition',
104
            'ge'      => 'buildCompareCondition',
105
            'lt'      => 'buildCompareCondition',
106
            'le'      => 'buildCompareCondition',
107
        ];
108
        if (empty($condition)) {
109
            return [];
110
        }
111
        if (!is_array($condition)) {
112
            throw new NotSupportedException('String conditions in where() are not supported by HiArt.');
113
        }
114
115
        if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ...
116
            $operator = strtolower($condition[0]);
117
            if (isset($builders[$operator])) {
118
                $method = $builders[$operator];
119
                array_shift($condition); // Shift build condition
120
121
                return $this->$method($operator, $condition);
122
            } else {
123
                throw new InvalidParamException('Found unknown operator in query: ' . $operator);
124
            }
125
        } else {
126
            return $this->buildHashCondition($condition);
127
        }
128
    }
129
130
    private function buildHashCondition($condition)
131
    {
132
        $parts = [];
133
        foreach ($condition as $attribute => $value) {
134
            if (is_array($value)) { // IN condition
135
                // $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...
136
                $parts[$attribute . 's'] = implode(',', $value);
137
            } else {
138
                $parts[$attribute] = $value;
139
            }
140
        }
141
142
        return $parts;
143
    }
144
145
    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...
146
    {
147
        return [$operands[0] . '_like' => $operands[1]];
148
    }
149
150
    private function buildCompareCondition($operator, $operands)
151
    {
152
        if (!isset($operands[0], $operands[1])) {
153
            throw new InvalidParamException("Operator '$operator' requires three operands.");
154
        }
155
156
        return [$operands[0] . '_' . $operator => $operands[1]];
157
    }
158
159
    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...
160
    {
161
        $parts = [];
162
        foreach ($operands as $operand) {
163
            if (is_array($operand)) {
164
                $parts = \yii\helpers\ArrayHelper::merge($this->buildCondition($operand), $parts);
165
            }
166
        }
167
        if (!empty($parts)) {
168
            return $parts;
169
        } else {
170
            return [];
171
        }
172
    }
173
174
    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...
175
    {
176
        throw new NotSupportedException('Between condition is not supported by HiArt.');
177
    }
178
179
    private function buildInCondition($operator, $operands)
180
    {
181
        if (!isset($operands[0], $operands[1])) {
182
            throw new InvalidParamException("Operator '$operator' requires two operands.");
183
        }
184
185
        list($column, $values) = $operands;
186
187
        if (count($column) > 1) {
188
            return $this->buildCompositeInCondition($operator, $column, $values);
189
        } elseif (is_array($column)) {
190
            $column = reset($column);
191
        }
192
193
        foreach ((array) $values as $i => $value) {
194
            if (is_array($value)) {
195
                $values[$i] = $value = isset($value[$column]) ? $value[$column] : null;
196
            }
197
            if ($value === null) {
198
                unset($values[$i]);
199
            }
200
        }
201
202
        return [$column . '_in' => $values];
203
    }
204
205
    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...
206
    {
207
        $key = array_shift($operands);
208
209
        return [$key => reset($operands)];
210
    }
211
212
    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...
213
    {
214
        throw new NotSupportedException('composite in is not supported by HiArt.');
215
    }
216
}
217