Completed
Pull Request — 3.x (#131)
by Paul
01:50
created

AbstractQuery::setFlag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 2
cts 2
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\SqlQuery;
10
11
use Aura\SqlQuery\Common\SubselectInterface;
12
13
/**
14
 *
15
 * Abstract query object.
16
 *
17
 * @package Aura.SqlQuery
18
 *
19
 */
20
abstract class AbstractQuery
21
{
22
    /**
23
     *
24
     * Data to be bound to the query.
25
     *
26
     * @var array
27
     *
28
     */
29
    protected $bind_values = array();
30
31
    /**
32
     *
33
     * The list of WHERE conditions.
34
     *
35
     * @var array
36
     *
37
     */
38
    protected $where = array();
39
40
    /**
41
     *
42
     * ORDER BY these columns.
43
     *
44
     * @var array
45
     *
46
     */
47
    protected $order_by = array();
48
49
    /**
50
     *
51
     * The list of flags.
52
     *
53
     * @var array
54
     *
55
     */
56
    protected $flags = array();
57
58
    /**
59
     *
60
     * A helper for quoting identifier names.
61
     *
62
     * @var Quoter
63
     *
64
     */
65
    protected $quoter;
66
67
    /**
68
     *
69
     * Prefix to use on placeholders for "sequential" bound values; used for
70
     * deconfliction when merging bound values from sub-selects, etc.
71
     *
72
     * @var mixed
73
     *
74
     */
75
    protected $seq_bind_prefix = '';
76
77
    /**
78
     *
79
     * Constructor.
80
     *
81
     * @param Quoter $quoter A helper for quoting identifier names.
82
     *
83
     * @param string $seq_bind_prefix A prefix for rewritten sequential-binding
84
     * placeholders (@see getSeqPlaceholder()).
85
     *
86
     */
87 387
    public function __construct(Quoter $quoter, $builder, $seq_bind_prefix = '')
88
    {
89 387
        $this->quoter = $quoter;
90 387
        $this->builder = $builder;
0 ignored issues
show
Bug introduced by
The property builder does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
91
        $this->seq_bind_prefix = $seq_bind_prefix;
92
    }
93
94
    /**
95
     *
96
     * Returns the prefix for rewritten sequential-binding placeholders
97
     * (@see getSeqPlaceholder()).
98
     *
99
     * @return string
100
     *
101
     */
102
    public function getSeqBindPrefix()
103
    {
104
        return $this->seq_bind_prefix;
105
    }
106
107
    /**
108
     *
109
     * Returns this query object as an SQL statement string.
110
     *
111
     * @return string
112
     *
113 5
     */
114
    public function __toString()
115 5
    {
116
        return $this->getStatement();
117
    }
118
119
    /**
120
     *
121
     * Returns this query object as an SQL statement string.
122
     *
123
     * @return string
124
     *
125
     */
126
    public function getStatement()
127
    {
128
        return $this->build();
129
    }
130
131
    /**
132
     *
133
     * Builds this query object into a string.
134
     *
135
     * @return string
136
     *
137
     */
138
    abstract protected function build();
139
140
    /**
141
     *
142
     * Returns the prefix to use when quoting identifier names.
143
     *
144
     * @return string
145
     *
146
     */
147
    public function getQuoteNamePrefix()
148
    {
149
        return $this->quoter->getQuoteNamePrefix();
150
    }
151
152
    /**
153
     *
154
     * Returns the suffix to use when quoting identifier names.
155
     *
156
     * @return string
157
     *
158
     */
159
    public function getQuoteNameSuffix()
160
    {
161
        return $this->quoter->getQuoteNameSuffix();
162
    }
163
164
    /**
165
     *
166
     * Binds multiple values to placeholders; merges with existing values.
167
     *
168
     * @param array $bind_values Values to bind to placeholders.
169
     *
170
     * @return $this
171
     *
172 61
     */
173
    public function bindValues(array $bind_values)
174 61
    {
175
        // array_merge() renumbers integer keys, which is bad for
176 61
        // question-mark placeholders
177
        foreach ($bind_values as $key => $val) {
178
            $this->bindValue($key, $val);
179
        }
180
        return $this;
181
    }
182
183
    /**
184
     *
185
     * Binds a single value to the query.
186
     *
187 50
     * @param string $name The placeholder name or number.
188
     *
189 50
     * @param mixed $value The value to bind to the placeholder.
190
     *
191 50
     * @return $this
192
     *
193
     */
194
    public function bindValue($name, $value)
195
    {
196
        $this->bind_values[$name] = $value;
197
        return $this;
198
    }
199
200
    /**
201
     *
202 16
     * Gets the values to bind to placeholders.
203
     *
204
     * @return array
205
     *
206
     */
207
    public function getBindValues()
208
    {
209 16
        return $this->bind_values;
210 16
    }
211
212
    /**
213
     *
214
     * Reset all values bound to named placeholders.
215
     *
216
     * @return $this
217
     *
218
     */
219
    public function resetBindValues()
220
    {
221
        $this->bind_values = array();
222
        return $this;
223 21
    }
224
225 21
    /**
226 21
     *
227
     * Sets or unsets specified flag.
228
     *
229
     * @param string $flag Flag to set or unset
230
     *
231
     * @param bool $enable Flag status - enabled or not (default true)
232
     *
233
     * @return null
234
     *
235
     */
236 106
    protected function setFlag($flag, $enable = true)
237
    {
238 106
        if ($enable) {
239
            $this->flags[$flag] = true;
240
        } else {
241
            unset($this->flags[$flag]);
242
        }
243
    }
244
245
    /**
246
     *
247
     * Returns true if the specified flag was enabled by setFlag().
248 15
     *
249
     * @param string $flag Flag to check
250 15
     *
251 15
     * @return bool
252
     *
253
     */
254
    protected function hasFlag($flag)
255
    {
256
        return isset($this->flags[$flag]);
257
    }
258
259
    /**
260
     *
261 213
     * Reset all query flags.
262
     *
263 213
     * @return $this
264 175
     *
265
     */
266
    public function resetFlags()
267
    {
268
        $this->flags = array();
269
        return $this;
270
    }
271
272
    /**
273
     *
274
     * Adds a WHERE condition to the query by AND or OR. If the condition has
275
     * ?-placeholders, additional arguments to the method will be bound to
276
     * those placeholders sequentially.
277
     *
278
     * @param string $andor Add the condition using this operator, typically
279
     * 'AND' or 'OR'.
280
     *
281 37
     * @param string $cond The WHERE condition.
282
     *
283 32
     * @param array ...$bind arguments to bind to placeholders
284 37
     *
285
     * @return $this
286 5
     *
287 37
     */
288 32
    protected function addWhere($andor, $cond, ...$bind)
289
    {
290
        $this->addClauseCondWithBind('where', $andor, $cond, $bind);
291
        return $this;
292
    }
293
294
    /**
295
     *
296
     * Adds conditions and binds values to a clause.
297
     *
298
     * @param string $clause The clause to work with, typically 'where' or
299 10
     * 'having'.
300
     *
301 10
     * @param string $andor Add the condition using this operator, typically
302
     * 'AND' or 'OR'.
303
     *
304
     * @param string $cond The WHERE condition.
305
306
     * @param array $bind arguments to bind to placeholders
307
     *
308
     * @return null
309
     *
310
     */
311 20
    protected function addClauseCondWithBind($clause, $andor, $cond, $bind)
312
    {
313 20
        $cond = $this->rebuildCondAndBindValues($cond, $bind);
314 20
315
        // add condition to clause; eg $this->where or $this->having
316
        $clause =& $this->$clause;
317
        if ($clause) {
318
            $clause[] = "$andor $cond";
319
        } else {
320
            $clause[] = $cond;
321
        }
322
    }
323
324
    /**
325
     *
326
     * Rebuilds a condition string, replacing sequential placeholders with
327
     * named placeholders, and binding the sequential values to the named
328
     * placeholders.
329
     *
330
     * @param string $cond The condition with sequential placeholders.
331
     *
332
     * @param array $bind_values The values to bind to the sequential
333 11
     * placeholders under their named versions.
334
     *
335
     * @return string The rebuilt condition string.
336 11
     *
337
     */
338
    protected function rebuildCondAndBindValues($cond, array $bind_values)
339
    {
340
        $cond = $this->quoter->quoteNamesIn($cond);
341
342
        // bind values against ?-mark placeholders, but because PDO is finicky
343
        // about the numbering of sequential placeholders, convert each ?-mark
344
        // to a named placeholder
345
        $parts = preg_split('/(\?)/', $cond, null, PREG_SPLIT_DELIM_CAPTURE);
346
        foreach ($parts as $key => $val) {
347
            if ($val != '?') {
348
                continue;
349
            }
350
351
            $bind_value = array_shift($bind_values);
352
            if ($bind_value instanceof SubselectInterface) {
353
                $parts[$key] = $bind_value->getStatement();
354
                $this->bind_values = array_merge(
355
                    $this->bind_values,
356 50
                    $bind_value->getBindValues()
357
                );
358
                continue;
359
            }
360
361 6
            $placeholder = $this->getSeqPlaceholder();
362 6
            $parts[$key] = ':' . $placeholder;
363 25
            $this->bind_values[$placeholder] = $bind_value;
364
        }
365 50
366 25
        $cond = implode('', $parts);
367 6
        return $cond;
368
    }
369
370
    /**
371
     *
372
     * Gets the current sequential placeholder name.
373
     *
374
     * @return string
375
     *
376
     */
377
    protected function getSeqPlaceholder()
378
    {
379
        $i = count($this->bind_values) + 1;
380
        return $this->seq_bind_prefix . "_{$i}_";
381
    }
382
383 31
    /**
384
     *
385
     * Adds a column order to the query.
386
     *
387
     * @param array $spec The columns and direction to order by.
388
     *
389
     * @return $this
390
     *
391
     */
392 10
    protected function addOrderBy(array $spec)
393 10
    {
394
        foreach ($spec as $col) {
395
            $this->order_by[] = $this->quoter->quoteNamesIn($col);
396
        }
397 31
        return $this;
398
    }
399
}
400