Completed
Pull Request — 3.x (#136)
by Paul
04:19 queued 02:13
created

AbstractQuery::getBindValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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\SelectInterface;
12
use Aura\SqlQuery\Common\QuoterInterface;
13
use Closure;
14
15
/**
16
 *
17
 * Abstract query object.
18
 *
19
 * @package Aura.SqlQuery
20
 *
21
 */
22
abstract class AbstractQuery
23
{
24
    /**
25
     *
26
     * Data to be bound to the query.
27
     *
28
     * @var array
29
     *
30
     */
31
    protected $bind_values = array();
32
33
    /**
34
     *
35
     * The list of WHERE conditions.
36
     *
37
     * @var array
38
     *
39
     */
40
    protected $where = array();
41
42
    /**
43
     *
44
     * ORDER BY these columns.
45
     *
46
     * @var array
47
     *
48
     */
49
    protected $order_by = array();
50
51
    /**
52
     *
53
     * The list of flags.
54
     *
55
     * @var array
56
     *
57
     */
58
    protected $flags = array();
59
60
    /**
61
     *
62
     * A helper for quoting identifier names.
63
     *
64
     * @var Quoter
65
     *
66
     */
67
    protected $quoter;
68
69
    /**
70
     *
71
     * Constructor.
72
     *
73
     * @param Quoter $quoter A helper for quoting identifier names.
74
     *
75
     */
76 417
    public function __construct(QuoterInterface $quoter, $builder)
77
    {
78 417
        $this->quoter = $quoter;
0 ignored issues
show
Documentation Bug introduced by
It seems like $quoter of type object<Aura\SqlQuery\Common\QuoterInterface> is incompatible with the declared type object<Aura\SqlQuery\Quoter> of property $quoter.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
79 417
        $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...
80 417
    }
81
82
    /**
83
     *
84
     * Returns this query object as an SQL statement string.
85
     *
86
     * @return string
87
     *
88
     */
89 243
    public function __toString()
90
    {
91 243
        return $this->getStatement();
92
    }
93
94
    /**
95
     *
96
     * Returns this query object as an SQL statement string.
97
     *
98
     * @return string
99
     *
100
     */
101 69
    public function getStatement()
102
    {
103 69
        return $this->build();
104
    }
105
106
    /**
107
     *
108
     * Builds this query object into a string.
109
     *
110
     * @return string
111
     *
112
     */
113
    abstract protected function build();
114
115
    /**
116
     *
117
     * Returns the prefix to use when quoting identifier names.
118
     *
119
     * @return string
120
     *
121
     */
122 267
    public function getQuoteNamePrefix()
123
    {
124 267
        return $this->quoter->getQuoteNamePrefix();
125
    }
126
127
    /**
128
     *
129
     * Returns the suffix to use when quoting identifier names.
130
     *
131
     * @return string
132
     *
133
     */
134 267
    public function getQuoteNameSuffix()
135
    {
136 267
        return $this->quoter->getQuoteNameSuffix();
137
    }
138
139
    /**
140
     *
141
     * Binds multiple values to placeholders; merges with existing values.
142
     *
143
     * @param array $bind_values Values to bind to placeholders.
144
     *
145
     * @return $this
146
     *
147
     */
148 41
    public function bindValues(array $bind_values)
149
    {
150
        // array_merge() renumbers integer keys, which is bad for
151
        // question-mark placeholders
152 41
        foreach ($bind_values as $key => $val) {
153 31
            $this->bindValue($key, $val);
154
        }
155 41
        return $this;
156
    }
157
158
    /**
159
     *
160
     * Binds a single value to the query.
161
     *
162
     * @param string $name The placeholder name or number.
163
     *
164
     * @param mixed $value The value to bind to the placeholder.
165
     *
166
     * @return $this
167
     *
168
     */
169 136
    public function bindValue($name, $value)
170
    {
171 136
        $this->bind_values[$name] = $value;
172 136
        return $this;
173
    }
174
175
    /**
176
     *
177
     * Gets the values to bind to placeholders.
178
     *
179
     * @return array
180
     *
181
     */
182 126
    public function getBindValues()
183
    {
184 126
        return $this->bind_values;
185
    }
186
187
    /**
188
     *
189
     * Reset all values bound to named placeholders.
190
     *
191
     * @return $this
192
     *
193
     */
194 15
    public function resetBindValues()
195
    {
196 15
        $this->bind_values = array();
197 15
        return $this;
198
    }
199
200
    /**
201
     *
202
     * Sets or unsets specified flag.
203
     *
204
     * @param string $flag Flag to set or unset
205
     *
206
     * @param bool $enable Flag status - enabled or not (default true)
207
     *
208
     * @return null
209
     *
210
     */
211 43
    protected function setFlag($flag, $enable = true)
212
    {
213 43
        if ($enable) {
214 43
            $this->flags[$flag] = true;
215
        } else {
216 5
            unset($this->flags[$flag]);
217
        }
218 43
    }
219
220
    /**
221
     *
222
     * Returns true if the specified flag was enabled by setFlag().
223
     *
224
     * @param string $flag Flag to check
225
     *
226
     * @return bool
227
     *
228
     */
229 10
    protected function hasFlag($flag)
230
    {
231 10
        return isset($this->flags[$flag]);
232
    }
233
234
    /**
235
     *
236
     * Reset all query flags.
237
     *
238
     * @return $this
239
     *
240
     */
241 20
    public function resetFlags()
242
    {
243 20
        $this->flags = array();
244 20
        return $this;
245
    }
246
247
    /**
248
     *
249
     * Adds conditions and binds values to a clause.
250
     *
251
     * @param string $clause The clause to work with, typically 'where' or
252
     * 'having'.
253
     *
254
     * @param string $andor Add the condition using this operator, typically
255
     * 'AND' or 'OR'.
256
     *
257
     * @param string $cond The WHERE condition.
258
     *
259
     * @param array $bind arguments to bind to placeholders
260
     *
261
     * @return null
262
     *
263
     */
264 80
    protected function addClauseCondWithBind($clause, $andor, $cond, $bind)
265
    {
266 80
        if ($cond instanceof Closure) {
267 10
            $this->addClauseCondClosure($clause, $andor, $cond);
268 10
            $this->bindValues($bind);
269 10
            return;
270
        }
271
272 80
        $cond = $this->quoter->quoteNamesIn($cond);
273 80
        $cond = $this->rebuildCondAndBindValues($cond, $bind);
274
275 80
        $clause =& $this->$clause;
276 80
        if ($clause) {
277 59
            $clause[] = "$andor $cond";
278
        } else {
279 80
            $clause[] = $cond;
280
        }
281 80
    }
282
283 10
    protected function addClauseCondClosure($clause, $andor, $closure)
284
    {
285
        // retain the prior set of conditions, and temporarily reset the clause
286
        // for the closure to work with (otherwise there will be an extraneous
287
        // opening AND/OR keyword)
288 10
        $set = $this->$clause;
289 10
        $this->$clause = [];
290
291
        // invoke the closure, which will re-populate the $this->$clause
292 10
        $closure($this);
293
294
        // are there new clause elements?
295 10
        if (! $this->$clause) {
296
            // no: restore the old ones, and done
297 10
            $this->$clause = $set;
298 10
            return;
299
        }
300
301
        // append an opening parenthesis to the prior set of conditions,
302
        // with AND/OR as needed ...
303 10
        if ($set) {
304 10
            $set[] = "{$andor} (";
305
        } else {
306 10
            $set[] = "(";
307
        }
308
309
        // append the new conditions to the set, with indenting
310 10
        foreach ($this->$clause as $cond) {
311 10
            $set[] = "    {$cond}";
312
        }
313 10
        $set[] = ")";
314
315
        // ... then put the full set of conditions back into $this->$clause
316 10
        $this->$clause = $set;
317 10
    }
318
319
    /**
320
     *
321
     * Rebuilds a condition string, replacing sequential placeholders with
322
     * named placeholders, and binding the sequential values to the named
323
     * placeholders.
324
     *
325
     * @param string $cond The condition with sequential placeholders.
326
     *
327
     * @param array $bind_values The values to bind to the sequential
328
     * placeholders under their named versions.
329
     *
330
     * @return string The rebuilt condition string.
331
     *
332
     */
333 130
    protected function rebuildCondAndBindValues($cond, array $bind_values)
334
    {
335 130
        $selects = [];
336
337 130
        foreach ($bind_values as $key => $val) {
338 80
            if ($val instanceof SelectInterface) {
339 10
                $selects[":{$key}"] = $val;
340
            } else {
341 80
                $this->bindValue($key, $val);
342
            }
343
        }
344
345 130
        foreach ($selects as $key => $select) {
346 10
            $selects[$key] = $select->getStatement();
347 10
            $this->bind_values = array_merge(
348 10
                $this->bind_values,
349 10
                $select->getBindValues()
350
            );
351
        }
352
353 130
        $cond = strtr($cond, $selects);
354 130
        return $cond;
355
    }
356
357
    /**
358
     *
359
     * Adds a column order to the query.
360
     *
361
     * @param array $spec The columns and direction to order by.
362
     *
363
     * @return $this
364
     *
365
     */
366 9
    protected function addOrderBy(array $spec)
367
    {
368 9
        foreach ($spec as $col) {
369 9
            $this->order_by[] = $this->quoter->quoteNamesIn($col);
370
        }
371 9
        return $this;
372
    }
373
}
374