Query::setOrder()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
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 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2017 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Db;
9
10
/**
11
 * An object representation of a SELECT statement.
12
 */
13
class Query {
14
    /**
15
     * @var string
16
     */
17
    private $from;
18
19
    /**
20
     * @var array The where clause.
21
     */
22
    private $where;
23
24
    /**
25
     * @var array A pointer to the current where clause.
26
     */
27
    private $currentWhere;
28
29
    /**
30
     * @var array Pointers to nested where brackets.
31
     */
32
    private $whereStack;
33
34
    /**
35
     * @var int
36
     */
37
    private $limit;
38
39
    /**
40
     * @var int
41
     */
42
    private $offset;
43
44
    /**
45
     * @var string[]
46
     */
47
    private $order;
48
49
    /**
50
     * Instantiate a new instance of the {@link Query} class.
51
     *
52
     * @param string $from The table to query.
53
     */
54 11
    public function __construct($from = '') {
55 11
        $this->from = $from;
56 11
        $this->where = [];
57 11
        $this->currentWhere = &$this->where;
58 11
        $this->whereStack = [];
59 11
    }
60
61
    /**
62
     * Begin an AND bracket group in the WHERE clause.
63
     *
64
     * @return $this
65
     * @see Query::end()
66
     */
67 5
    public function beginAnd() {
68 5
        $this->beginBracket(Db::OP_AND);
69 5
        return $this;
70
    }
71
72
    /**
73
     * Begin an OR bracket group in the WHERE clause.
74
     *
75
     * @return $this
76
     * @see Query::end()
77
     */
78 4
    public function beginOr() {
79 4
        $this->beginBracket(Db::OP_OR);
80 4
        return $this;
81
    }
82
83
    /**
84
     * Begin a bracket group in the WHERE clause.
85
     *
86
     * @param string $op One of the **DB::OP_*** constants.
87
     * @return $this
88
     */
89 8
    private function beginBracket($op) {
90 8
        $this->currentWhere[] = [$op => []];
91 8
        $this->whereStack[] = &$this->currentWhere;
92 8
        end($this->currentWhere);
93 8
        $this->currentWhere = &$this->currentWhere[key($this->currentWhere)][$op];
94
95 8
        return $this;
96
    }
97
98
    /**
99
     * End a bracket group.
100
     *
101
     * @return $this
102
     * @see Query::beginAnd(), Query::beginOr()
103
     */
104 8
    public function end() {
105
        // First unset the reference so it doesn't overwrite the original where clause.
106 8
        unset($this->currentWhere);
107
108
        // Move the pointer in the where stack back one level.
109 8
        if (empty($this->whereStack)) {
110
            trigger_error("Call to Query->end() without a corresponding call to Query->begin*().", E_USER_NOTICE);
111
            $this->currentWhere = &$this->where;
112
        } else {
113 8
            $key = key(end($this->whereStack));
114 8
            $this->currentWhere = &$this->whereStack[$key];
115 8
            unset($this->whereStack[$key]);
116
117
        }
118 8
        return $this;
119
    }
120
121
    /**
122
     * Add a WHERE condition to the query.
123
     *
124
     * A basic call to this method specifies a column name and a value.
125
     *
126
     * ```php
127
     * $query->where('id', 123);
128
     * ```
129
     *
130
     * If you specify just a value then the query will perform an equality match. If you want to specify a different
131
     * operator then you can pass in an array for {@link $value} with the key being the operator and the value being the
132
     * value to filter on.
133
     *
134
     * ```php
135
     * $query->where('count', [Db::GT => 100]);
136
     * ```
137
     *
138
     * @param string $column Either the name of the column or an array representing several query operators.
139
     * @param mixed $value The value to match to the column. If using the array form of {@link $column} then this parameter
140
     * can be omitted.
141
     * @return $this
142
     */
143 11
    public function addWhere($column, $value) {
144 11
        if (array_key_exists($column, $this->currentWhere)) {
145 2
            if (!is_array($this->currentWhere[$column])) {
146
                // This is a basic equality statement.
147 2
                $this->currentWhere[$column] = [Db::OP_EQ => $this->currentWhere[$column]];
148 2
            } elseif (array_key_exists(0, $this->currentWhere[$column])) {
149
                // This is a basic IN clause.
150 1
                $this->currentWhere[$column] = [Db::OP_IN => $this->currentWhere[$column]];
151
            }
152
153
            // Massage the value for proper syntax.
154 2
            if (!is_array($value)) {
155 2
                $value = [Db::OP_EQ => $value];
156 2
            } elseif (array_key_exists(0, $value)) {
157 1
                $value = [Db::OP_IN => $value];
158
            }
159
160 2
            $this->currentWhere[$column] = array_merge($this->currentWhere[$column], $value);
161
        } else {
162 11
            $this->currentWhere[$column] = $value;
163
        }
164 11
        return $this;
165
    }
166
167
    /**
168
     * Add a like statement to the current where clause.
169
     *
170
     * @param string $column The name of the column to compare.
171
     * @param string $value The like query.
172
     * @return $this
173
     */
174
    public function addLike($column, $value) {
175
        $r = $this->addWhere($column, [Db::OP_LIKE => $value]);
176
        return $r;
177
    }
178
179
    /**
180
     * Add an in statement to the current where clause.
181
     *
182
     * @param string $column The name of the column to compare.
183
     * @param array $values The in list to check against.
184
     * @return $this
185
     */
186
    public function addIn($column, array $values) {
187
        $r = $this->addWhere($column, [Db::OP_IN, $values]);
188
        return $r;
189
    }
190
191
    /**
192
     * Add an array of where statements.
193
     *
194
     * This method takes an array where the keys represent column names and the values represent filter values.
195
     *
196
     * ```php
197
     * $query->where([
198
     *     'parentID' => 123,
199
     *     'count' => [Db::GT => 0]
200
     * ]);
201
     * ```
202
     *
203
     * @param array $where The array of where statements to add to the query.
204
     * @return $this
205
     * @see Query::addWhere()
206
     */
207 1
    public function addWheres(array $where) {
208 1
        foreach ($where as $column => $value) {
209 1
            $this->addWhere($column, $value);
210
        }
211 1
        return $this;
212
    }
213
214
    /**
215
     * Return an array representation of this query.
216
     *
217
     * @return array Returns an array with keys representing the query parts.
218
     */
219 7
    public function toArray() {
220
        $r = [
221 7
            'from' => $this->from,
222 7
            'where' => $this->where,
223 7
            'order' => $this->order,
224 7
            'limit' => $this->limit,
225 7
            'offset' => $this->offset
226
        ];
227
228 7
        return $r;
229
    }
230
231
    /**
232
     * Execute this query against a database.
233
     *
234
     * @param Db $db The database to query.
235
     * @return \PDOStatement Returns the query result.
236
     */
237 4
    public function exec(Db $db) {
238
        $options = [
239 4
            'limit' => $this->limit,
240 4
            'offset' => $this->offset
241
        ];
242
243 4
        $r = $db->get($this->from, $this->where, $options);
244 4
        return $r;
245
    }
246
247
    /**
248
     * Get the name of the table that is being queried.
249
     *
250
     * @return string Returns the from.
251
     */
252
    public function getFrom() {
253
        return $this->from;
254
    }
255
256
    /**
257
     * Set the name of the table that is being queried.
258
     *
259
     * @param string $from A table name.
260
     * @return $this
261
     */
262
    public function setFrom($from) {
263
        $this->from = $from;
264
        return $this;
265
    }
266
267
    /**
268
     * Get the limit.
269
     *
270
     * @return int Returns the limit.
271
     */
272
    public function getLimit() {
273
        return $this->limit;
274
    }
275
276
    /**
277
     * Set the limit.
278
     *
279
     * @param int $limit The new limit.
280
     * @return $this
281
     */
282
    public function setLimit($limit) {
283
        $this->limit = $limit;
284
        return $this;
285
    }
286
287
    /**
288
     * Get the offset.
289
     *
290
     * @return int Returns the offset.
291
     */
292
    public function getOffset() {
293
        return $this->offset;
294
    }
295
296
    /**
297
     * Set the offset.
298
     *
299
     * @param int $offset The new offset.
300
     * @return $this
301
     */
302
    public function setOffset($offset) {
303
        $this->offset = $offset;
304
        return $this;
305
    }
306
307
    /**
308
     * Get the sort order.
309
     *
310
     * @return string[] Returns an array of column names, optionally prefixed with "-" to denote descending order.
311
     */
312
    public function getOrder() {
313
        return $this->order;
314
    }
315
316
    /**
317
     * Set the sort order.
318
     *
319
     * @param string ...$columns The column names to sort by, optionally prefixed with "-" to denote descending order.
320
     * @return $this
321
     */
322
    public function setOrder(...$columns) {
323
        $this->order = $columns;
324
        return $this;
325
    }
326
327
    /**
328
     * Add one or more columns to the the order array.
329
     *
330
     * @param string ...$columns Column names optionally starting with a "-".
331
     * @return $this
332
     */
333
    public function addOrder(...$columns) {
334
        $this->order = array_merge($this->order, $columns);
335
        return $this;
336
    }
337
}
338