Completed
Push — 3.x-named-placeholders-only ( 913a85...bc7948 )
by Paul
01:58
created

AbstractQuery::fixCondWithBind()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 17
cts 17
cp 1
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 14
nc 6
nop 2
crap 4
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
use Aura\SqlQuery\Common\QuoterInterface;
13
14
/**
15
 *
16
 * Abstract query object.
17
 *
18
 * @package Aura.SqlQuery
19
 *
20
 */
21
abstract class AbstractQuery
22
{
23
    /**
24
     *
25
     * Data to be bound to the query.
26
     *
27
     * @var array
28
     *
29
     */
30
    protected $bind_values = array();
31
32
    /**
33
     *
34
     * The list of WHERE conditions.
35
     *
36
     * @var array
37
     *
38
     */
39
    protected $where = array();
40
41
    /**
42
     *
43
     * ORDER BY these columns.
44
     *
45
     * @var array
46
     *
47
     */
48
    protected $order_by = array();
49
50
    /**
51
     *
52
     * The list of flags.
53
     *
54
     * @var array
55
     *
56
     */
57
    protected $flags = array();
58
59
    /**
60
     *
61
     * A helper for quoting identifier names.
62
     *
63
     * @var Quoter
64
     *
65
     */
66
    protected $quoter;
67
68
    /**
69
     *
70
     * Prefix to use on placeholders for "sequential" bound values; used for
71
     * deconfliction when merging bound values from sub-selects, etc.
72
     *
73
     * @var mixed
74
     *
75
     */
76
    protected $seq_bind_prefix = '';
77
78
    /**
79
     *
80
     * Constructor.
81
     *
82
     * @param Quoter $quoter A helper for quoting identifier names.
83
     *
84
     * @param string $seq_bind_prefix A prefix for rewritten sequential-binding
85
     * placeholders (@see getSeqPlaceholder()).
86
     *
87
     */
88 408
    public function __construct(QuoterInterface $quoter, $builder, $seq_bind_prefix = '')
89
    {
90 408
        $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...
91 408
        $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...
92 408
        $this->seq_bind_prefix = $seq_bind_prefix;
93 408
    }
94
95
    /**
96
     *
97
     * Returns the prefix for rewritten sequential-binding placeholders
98
     * (@see getSeqPlaceholder()).
99
     *
100
     * @return string
101
     *
102
     */
103 1
    public function getSeqBindPrefix()
104
    {
105 1
        return $this->seq_bind_prefix;
106
    }
107
108
    /**
109
     *
110
     * Returns this query object as an SQL statement string.
111
     *
112
     * @return string
113
     *
114
     */
115 243
    public function __toString()
116
    {
117 243
        return $this->getStatement();
118
    }
119
120
    /**
121
     *
122
     * Returns this query object as an SQL statement string.
123
     *
124
     * @return string
125
     *
126
     */
127 69
    public function getStatement()
128
    {
129 69
        return $this->build();
130
    }
131
132
    /**
133
     *
134
     * Builds this query object into a string.
135
     *
136
     * @return string
137
     *
138
     */
139
    abstract protected function build();
140
141
    /**
142
     *
143
     * Returns the prefix to use when quoting identifier names.
144
     *
145
     * @return string
146
     *
147
     */
148 257
    public function getQuoteNamePrefix()
149
    {
150 257
        return $this->quoter->getQuoteNamePrefix();
151
    }
152
153
    /**
154
     *
155
     * Returns the suffix to use when quoting identifier names.
156
     *
157
     * @return string
158
     *
159
     */
160 257
    public function getQuoteNameSuffix()
161
    {
162 257
        return $this->quoter->getQuoteNameSuffix();
163
    }
164
165
    /**
166
     *
167
     * Binds multiple values to placeholders; merges with existing values.
168
     *
169
     * @param array $bind_values Values to bind to placeholders.
170
     *
171
     * @return $this
172
     *
173
     */
174 31
    public function bindValues(array $bind_values)
175
    {
176
        // array_merge() renumbers integer keys, which is bad for
177
        // question-mark placeholders
178 31
        foreach ($bind_values as $key => $val) {
179 31
            $this->bindValue($key, $val);
180 31
        }
181 31
        return $this;
182
    }
183
184
    /**
185
     *
186
     * Binds a single value to the query.
187
     *
188
     * @param string $name The placeholder name or number.
189
     *
190
     * @param mixed $value The value to bind to the placeholder.
191
     *
192
     * @return $this
193
     *
194
     */
195 136
    public function bindValue($name, $value)
196
    {
197 136
        $this->bind_values[$name] = $value;
198 136
        return $this;
199
    }
200
201
    /**
202
     *
203
     * Gets the values to bind to placeholders.
204
     *
205
     * @return array
206
     *
207
     */
208 126
    public function getBindValues()
209
    {
210 126
        return $this->bind_values;
211
    }
212
213
    /**
214
     *
215
     * Reset all values bound to named placeholders.
216
     *
217
     * @return $this
218
     *
219
     */
220 15
    public function resetBindValues()
221
    {
222 15
        $this->bind_values = array();
223 15
        return $this;
224
    }
225
226
    /**
227
     *
228
     * Sets or unsets specified flag.
229
     *
230
     * @param string $flag Flag to set or unset
231
     *
232
     * @param bool $enable Flag status - enabled or not (default true)
233
     *
234
     * @return null
235
     *
236
     */
237 43
    protected function setFlag($flag, $enable = true)
238
    {
239 43
        if ($enable) {
240 43
            $this->flags[$flag] = true;
241 43
        } else {
242 5
            unset($this->flags[$flag]);
243
        }
244 43
    }
245
246
    /**
247
     *
248
     * Returns true if the specified flag was enabled by setFlag().
249
     *
250
     * @param string $flag Flag to check
251
     *
252
     * @return bool
253
     *
254
     */
255 10
    protected function hasFlag($flag)
256
    {
257 10
        return isset($this->flags[$flag]);
258
    }
259
260
    /**
261
     *
262
     * Reset all query flags.
263
     *
264
     * @return $this
265
     *
266
     */
267 20
    public function resetFlags()
268
    {
269 20
        $this->flags = array();
270 20
        return $this;
271
    }
272
273
    /**
274
     *
275
     * Adds conditions and binds values to a clause.
276
     *
277
     * @param string $clause The clause to work with, typically 'where' or
278
     * 'having'.
279
     *
280
     * @param string $andor Add the condition using this operator, typically
281
     * 'AND' or 'OR'.
282
     *
283
     * @param string $cond The WHERE condition.
284
     *
285
     * @param array $bind arguments to bind to placeholders
286
     *
287
     * @return null
288
     *
289
     */
290 70
    protected function addClauseCondWithBind($clause, $andor, $cond, $bind)
291
    {
292 70
        $cond = $this->quoter->quoteNamesIn($cond);
293 70
        $cond = $this->fixCondWithBind($cond, $bind);
294
295 70
        $clause =& $this->$clause;
296 70
        if ($clause) {
297 49
            $clause[] = "$andor $cond";
298 49
        } else {
299 70
            $clause[] = $cond;
300
        }
301
302 70
    }
303
304 120
    protected function fixCondWithBind($cond, array $bind)
305
    {
306 120
        $selects = [];
307
308 120
        foreach ($bind as $key => $val) {
309 80
            if ($val instanceof SubselectInterface) {
310 10
                $selects[":{$key}"] = $val;
311 10
            } else {
312 75
                $this->bindValue($key, $val);
313
            }
314 120
        }
315
316 120
        foreach ($selects as $key => $select) {
317 10
            $selects[$key] = $select->getStatement();
318 10
            $this->bind_values = array_merge(
319 10
                $this->bind_values,
320 10
                $select->getBindValues()
321 10
            );
322 120
        }
323
324 120
        $cond = strtr($cond, $selects);
325 120
        return $cond;
326
    }
327
328
    /**
329
     *
330
     * Gets the current sequential placeholder name.
331
     *
332
     * @return string
333
     *
334
     */
335
    protected function getSeqPlaceholder()
336
    {
337
        $i = count($this->bind_values) + 1;
338
        return $this->seq_bind_prefix . "_{$i}_";
339
    }
340
341
    /**
342
     *
343
     * Adds a column order to the query.
344
     *
345
     * @param array $spec The columns and direction to order by.
346
     *
347
     * @return $this
348
     *
349
     */
350 9
    protected function addOrderBy(array $spec)
351
    {
352 9
        foreach ($spec as $col) {
353 9
            $this->order_by[] = $this->quoter->quoteNamesIn($col);
354 9
        }
355 9
        return $this;
356
    }
357
}
358