Completed
Push — resets ( d2f77b )
by Paul
02:06
created

Insert::getLastInsertIdName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
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\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 mixed,...  $val Optional: a value to bind to the placeholder.
0 ignored issues
show
Documentation introduced by
The doc-type mixed,... could not be parsed: Expected "|" or "end of type", but got "," at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
Bug introduced by
There is no parameter named $val. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
164
     *
165
     * @return $this
166
     *
167
     */
168 20
    public function col($col)
169
    {
170 20
        return call_user_func_array(array($this, 'addCol'), func_get_args());
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