Completed
Push — 3.x ( bfc500...4ede47 )
by Hari
9s
created

Insert::into()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
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\Common;
10
11
use Aura\SqlQuery\AbstractDmlQuery;
12
use Aura\SqlQuery\Exception;
13
14
/**
15
 *
16
 * An object for INSERT queries.
17
 *
18
 * @package Aura.SqlQuery
19
 *
20
 */
21
class Insert extends AbstractDmlQuery implements InsertInterface
22
{
23
    /**
24
     *
25
     * The table to insert into.
26
     *
27
     * @var string
28
     *
29
     */
30
    protected $into;
31
32
    /**
33
     *
34
     * A map of fully-qualified `table.column` names to last-insert-id names.
35
     * This is used to look up the right last-insert-id name for a given table
36
     * and column. Generally useful only for extended tables in Posgres.
37
     *
38
     * @var array
39
     *
40
     */
41
    protected $last_insert_id_names;
42
43
    /**
44
     *
45
     * The current row-number we are adding column values for. This comes into
46
     * play only with bulk inserts.
47
     *
48
     * @var int
49
     *
50
     */
51
    protected $row = 0;
52
53
    /**
54
     *
55
     * A collection of `$col_values` for previous rows in bulk inserts.
56
     *
57
     * @var array
58
     *
59
     */
60
    protected $col_values_bulk = array();
61
62
    /**
63
     *
64
     * A collection of `$bind_values` for previous rows in bulk inserts.
65
     *
66
     * @var array
67
     *
68
     */
69
    protected $bind_values_bulk = array();
70
71
    /**
72
     *
73
     * The order in which columns will be bulk-inserted; this is taken from the
74
     * very first inserted row.
75
     *
76
     * @var array
77
     *
78
     */
79
    protected $col_order = array();
80
81
    /**
82
     *
83
     * Sets the map of fully-qualified `table.column` names to last-insert-id
84
     * names. Generally useful only for extended tables in Posgres.
85
     *
86
     * @param array $last_insert_id_names The list of ID names.
87
     *
88
     */
89 76
    public function setLastInsertIdNames(array $last_insert_id_names)
90
    {
91 76
        $this->last_insert_id_names = $last_insert_id_names;
92 76
    }
93
94
    /**
95
     *
96
     * Sets the table to insert into.
97
     *
98
     * @param string $into The table to insert into.
99
     *
100
     * @return $this
101
     *
102
     */
103 56
    public function into($into)
104
    {
105
        // don't quote yet, we might need it for getLastInsertIdName()
106 56
        $this->into = $into;
107 56
        return $this;
108
    }
109
110
    /**
111
     *
112
     * Builds this query object into a string.
113
     *
114
     * @return string
115
     *
116
     */
117 30
    protected function build()
118
    {
119
        return 'INSERT'
120 30
            . $this->buildFlags()
121 30
            . $this->buildInto()
122 30
            . $this->buildValuesForInsert()
123 30
            . $this->buildReturning();
124
    }
125
126
    /**
127
     *
128
     * Builds the INTO clause.
129
     *
130
     * @return string
131
     *
132
     */
133 41
    protected function buildInto()
134
    {
135 41
        return " INTO " . $this->quoter->quoteName($this->into);
136
    }
137
138
    /**
139
     *
140
     * Returns the proper name for passing to `PDO::lastInsertId()`.
141
     *
142
     * @param string $col The last insert ID column.
143
     *
144
     * @return mixed Normally null, since most drivers do not need a name;
145
     * alternatively, a string from `$last_insert_id_names`.
146
     *
147
     */
148 10
    public function getLastInsertIdName($col)
149
    {
150 10
        $key = $this->into . '.' . $col;
151 10
        if (isset($this->last_insert_id_names[$key])) {
152 5
            return $this->last_insert_id_names[$key];
153
        }
154 5
    }
155
156
    /**
157
     *
158
     * Sets one column value placeholder; if an optional second parameter is
159
     * passed, that value is bound to the placeholder.
160
     *
161
     * @param string $col The column name.
162
     *
163
     * @param array $value Optional: a value to bind to the placeholder.
164
     *
165
     * @return $this
166
     *
167
     */
168 20
    public function col($col, ...$value)
169
    {
170 20
        return $this->addCol($col, ...$value);
171
    }
172
173
    /**
174
     *
175
     * Sets multiple column value placeholders. If an element is a key-value
176
     * pair, the key is treated as the column name and the value is bound to
177
     * that column.
178
     *
179
     * @param array $cols A list of column names, optionally as key-value
180
     * pairs where the key is a column name and the value is a bind value for
181
     * that column.
182
     *
183
     * @return $this
184
     *
185
     */
186 46
    public function cols(array $cols)
187
    {
188 46
        return $this->addCols($cols);
189
    }
190
191
    /**
192
     *
193
     * Sets a column value directly; the value will not be escaped, although
194
     * fully-qualified identifiers in the value will be quoted.
195
     *
196
     * @param string $col   The column name.
197
     *
198
     * @param string $value The column value expression.
199
     *
200
     * @return $this
201
     *
202
     */
203 31
    public function set($col, $value)
204
    {
205 31
        return $this->setCol($col, $value);
206
    }
207
208
    /**
209
     *
210
     * Gets the values to bind to placeholders.
211
     *
212
     * @return array
213
     *
214
     */
215 31
    public function getBindValues()
216
    {
217 31
        return array_merge(parent::getBindValues(), $this->bind_values_bulk);
218
    }
219
220
    /**
221
     *
222
     * Adds multiple rows for bulk insert.
223
     *
224
     * @param array $rows An array of rows, where each element is an array of
225
     * column key-value pairs. The values are bound to placeholders.
226
     *
227
     * @return $this
228
     *
229
     */
230 15
    public function addRows(array $rows)
231
    {
232 15
        foreach ($rows as $cols) {
233 15
            $this->addRow($cols);
234 15
        }
235 15
        if ($this->row > 1) {
236 10
            $this->finishRow();
237 10
        }
238 15
        return $this;
239
    }
240
241
    /**
242
     *
243
     * Add one row for bulk insert; increments the row counter and optionally
244
     * adds columns to the new row.
245
     *
246
     * When adding the first row, the counter is not incremented.
247
     *
248
     * After calling `addRow()`, you can further call `col()`, `cols()`, and
249
     * `set()` to work with the newly-added row. Calling `addRow()` again will
250
     * finish off the current row and start a new one.
251
     *
252
     * @param array $cols An array of column key-value pairs; the values are
253
     * bound to placeholders.
254
     *
255
     * @return $this
256
     *
257
     */
258 30
    public function addRow(array $cols = array())
259
    {
260 30
        if (! $this->col_values) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->col_values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
261 15
            return $this->cols($cols);
262
        }
263
264 25
        if (! $this->col_order) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->col_order of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
265 25
            $this->col_order = array_keys($this->col_values);
266 25
        }
267
268 25
        $this->finishRow();
269 25
        $this->row ++;
270 25
        $this->cols($cols);
271 25
        return $this;
272
    }
273
274
    /**
275
     *
276
     * Finishes off the current row in a bulk insert, collecting the bulk
277
     * values and resetting for the next row.
278
     *
279
     * @return null
280
     *
281
     */
282 25
    protected function finishRow()
283
    {
284 25
        if (! $this->col_values) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->col_values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
285 15
            return;
286
        }
287
288 25
        foreach ($this->col_order as $col) {
289 25
            $this->finishCol($col);
290 25
        }
291
292 25
        $this->col_values = array();
293 25
        $this->bind_values = array();
294 25
    }
295
296
    /**
297
     *
298
     * Finishes off a single column of the current row in a bulk insert.
299
     *
300
     * @param string $col The column to finish off.
301
     *
302
     * @return null
303
     *
304
     * @throws Exception on named column missing from row.
305
     *
306
     */
307 25
    protected function finishCol($col)
308
    {
309 25
        if (! array_key_exists($col, $this->col_values)) {
310 5
            throw new Exception("Column $col missing from row {$this->row}.");
311
        }
312
313
        // get the current col_value
314 25
        $value = $this->col_values[$col];
315
316
        // is it *not* a placeholder?
317 25
        if (substr($value, 0, 1) != ':') {
318
            // copy the value as-is
319 15
            $this->col_values_bulk[$this->row][$col] = $value;
320 15
            return;
321
        }
322
323
        // retain col_values in bulk with the row number appended
324 25
        $this->col_values_bulk[$this->row][$col] = "{$value}_{$this->row}";
325
326
        // the existing placeholder name without : or row number
327 25
        $name = substr($value, 1);
328
329
        // retain bind_value in bulk with new placeholder
330 25
        if (array_key_exists($name, $this->bind_values)) {
331 25
            $this->bind_values_bulk["{$name}_{$this->row}"] = $this->bind_values[$name];
332 25
        }
333 25
    }
334
335
    /**
336
     *
337
     * Builds the inserted columns and values of the statement.
338
     *
339
     * @return string
340
     *
341
     */
342 41
    protected function buildValuesForInsert()
343
    {
344 41
        if ($this->row) {
345 20
            return $this->buildValuesForBulkInsert();
346
        }
347
348
        return ' ('
349 21
            . $this->indentCsv(array_keys($this->col_values))
350 21
            . PHP_EOL . ') VALUES ('
351 21
            . $this->indentCsv(array_values($this->col_values))
352 21
            . PHP_EOL . ')';
353
    }
354
355
    /**
356
     *
357
     * Builds the bulk-inserted columns and values of the statement.
358
     *
359
     * @return string
360
     *
361
     */
362 20
    protected function buildValuesForBulkInsert()
363
    {
364 20
        $this->finishRow();
365 20
        $cols = "    (" . implode(', ', $this->col_order) . ")";
366 20
        $vals = array();
367 20
        foreach ($this->col_values_bulk as $row_values) {
368 20
            $vals[] = "    (" . implode(', ', $row_values) . ")";
369 20
        }
370 20
        return PHP_EOL . $cols . PHP_EOL
371 20
            . "VALUES" . PHP_EOL
372 20
            . implode("," . PHP_EOL, $vals);
373
    }
374
}
375