Completed
Pull Request — master (#1175)
by
unknown
02:05
created

PdoAdapter::getDefaultValueDefinition()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 0
cp 0
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 6
nc 6
nop 1
crap 30
1
<?php
2
/**
3
 * Phinx
4
 *
5
 * (The MIT license)
6
 * Copyright (c) 2015 Rob Morgan
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated * documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
25
 *
26
 * @package    Phinx
27
 * @subpackage Phinx\Db\Adapter
28
 */
29
namespace Phinx\Db\Adapter;
30
31
use BadMethodCallException;
32
use Phinx\Db\Table;
33
use Phinx\Db\Table\Column;
34
use Phinx\Migration\MigrationInterface;
35
36
/**
37
 * Phinx PDO Adapter.
38
 *
39
 * @author Rob Morgan <[email protected]>
40
 */
41
abstract class PdoAdapter extends AbstractAdapter
42
{
43
    /**
44
     * @var \PDO|null
45
     */
46
    protected $connection;
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 287
    public function setOptions(array $options)
52
    {
53 287
        parent::setOptions($options);
54
55 287
        if (isset($options['connection'])) {
56 3
            $this->setConnection($options['connection']);
57 3
        }
58
59 287
        return $this;
60
    }
61
62
    /**
63
     * Sets the database connection.
64
     *
65
     * @param \PDO $connection Connection
66
     * @return AdapterInterface
67
     */
68 193
    public function setConnection(\PDO $connection)
69
    {
70 193
        $this->connection = $connection;
71
72
        // Create the schema table if it doesn't already exist
73 193
        if (!$this->hasSchemaTable()) {
74 191
            $this->createSchemaTable();
75 191
        } else {
76 74
            $table = new Table($this->getSchemaTableName(), [], $this);
77 74
            if (!$table->hasColumn('migration_name')) {
78
                $table
79
                    ->addColumn(
80
                        'migration_name',
81
                        'string',
82
                        ['limit' => 100, 'after' => 'version', 'default' => null, 'null' => true]
83
                    )
84
                    ->save();
85
            }
86 74
            if (!$table->hasColumn('breakpoint')) {
87
                $table
88
                    ->addColumn('breakpoint', 'boolean', ['default' => false])
89
                    ->save();
90
            }
91
        }
92
93 193
        return $this;
94
    }
95
96
    /**
97
     * Gets the database connection
98
     *
99
     * @return \PDO
100
     */
101 191
    public function getConnection()
102
    {
103 191
        if ($this->connection === null) {
104 189
            $this->connect();
105 189
        }
106 191
        return $this->connection;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 1
    public function connect()
113
    {
114 1
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function disconnect()
120
    {
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 218
    public function execute($sql)
127
    {
128 218
        if ($this->isDryRunEnabled()) {
129 3
            $this->getOutput()->writeln($sql);
130 3
            return 0;
131
        }
132
133 217
        return $this->getConnection()->exec($sql);
134
    }
135
136
    /**
137
     * Executes a query and returns PDOStatement.
138
     *
139
     * @param string $sql SQL
140
     * @return \PDOStatement
141
     */
142 220
    public function query($sql)
143
    {
144 220
        return $this->getConnection()->query($sql);
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150 151
    public function fetchRow($sql)
151
    {
152 151
        $result = $this->query($sql);
153 151
        return $result->fetch();
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159 213
    public function fetchAll($sql)
160
    {
161 213
        $rows = [];
162 213
        $result = $this->query($sql);
163 213
        while ($row = $result->fetch()) {
164 208
            $rows[] = $row;
165 208
        }
166 213
        return $rows;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172 1
    public function insert(Table $table, $row)
173
    {
174 1
        $sql = sprintf(
175 1
            "INSERT INTO %s ",
176 1
            $this->quoteTableName($table->getName())
177 1
        );
178
179 1
        $columns = array_keys($row);
180 1
        $sql .= "(". implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ")";
181 1
        $sql .= " VALUES (" . implode(', ', array_fill(0, count($columns), '?')) . ")";
182
183 1
        $stmt = $this->getConnection()->prepare($sql);
184 1
        $stmt->execute(array_values($row));
185 1
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190 11
    public function bulkinsert(Table $table, $rows)
191
    {
192 11
        $sql = sprintf(
193 11
            "INSERT INTO %s ",
194 11
            $this->quoteTableName($table->getName())
195 11
        );
196
197 11
        $current = current($rows);
198 11
        $keys = array_keys($current);
199 11
        $sql .= "(". implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ") VALUES";
200
201 11
        $vals = [];
202 11
        foreach ($rows as $row) {
203 11
            foreach ($row as $v) {
204 11
                $vals[] = $v;
205 11
            }
206 11
        }
207
208 11
        $count_keys = count($keys);
209 11
        $query = "(" . implode(', ', array_fill(0, $count_keys, '?')) . ")";
210
211 11
        $count_vars = count($rows);
212 11
        $queries = array_fill(0, $count_vars, $query);
213 11
        $sql .= implode(',', $queries);
214
215 11
        $stmt = $this->getConnection()->prepare($sql);
216 11
        $stmt->execute($vals);
217 11
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222 5
    public function getVersions()
223
    {
224 5
        $rows = $this->getVersionLog();
225
226 5
        return array_keys($rows);
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232 8
    public function getVersionLog()
233
    {
234 8
        $result = [];
235
236 8
        switch ($this->options['version_order']) {
237 8
            case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
238 6
                $orderBy = 'version ASC';
239 6
                break;
240 2
            case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
241 1
                $orderBy = 'start_time ASC, version ASC';
242 1
                break;
243 1
            default:
244 1
                throw new \RuntimeException('Invalid version_order configuration option');
245 8
        }
246
247 7
        $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->getSchemaTableName(), $orderBy));
248 7
        foreach ($rows as $version) {
249 7
            $result[$version['version']] = $version;
250 7
        }
251
252 7
        return $result;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 5
    public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
259
    {
260 5
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
261
            // up
262 5
            $sql = sprintf(
263 5
                "INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
264 5
                $this->getSchemaTableName(),
265 5
                $this->quoteColumnName('version'),
266 5
                $this->quoteColumnName('migration_name'),
267 5
                $this->quoteColumnName('start_time'),
268 5
                $this->quoteColumnName('end_time'),
269 5
                $this->quoteColumnName('breakpoint'),
270 5
                $migration->getVersion(),
271 5
                substr($migration->getName(), 0, 100),
272 5
                $startTime,
273 5
                $endTime,
274 5
                $this->castToBool(false)
275 5
            );
276
277 5
            $this->execute($sql);
278 5
        } else {
279
            // down
280 3
            $sql = sprintf(
281 3
                "DELETE FROM %s WHERE %s = '%s'",
282 3
                $this->getSchemaTableName(),
283 3
                $this->quoteColumnName('version'),
284 3
                $migration->getVersion()
285 3
            );
286
287 3
            $this->execute($sql);
288
        }
289
290 5
        return $this;
291
    }
292
293
    /**
294
     * @inheritDoc
295
     */
296 1
    public function toggleBreakpoint(MigrationInterface $migration)
297
    {
298 1
        $this->query(
299 1
            sprintf(
300 1
                'UPDATE %1$s SET %2$s = CASE %2$s WHEN %3$s THEN %4$s ELSE %3$s END, %7$s = %7$s WHERE %5$s = \'%6$s\';',
301 1
                $this->getSchemaTableName(),
302 1
                $this->quoteColumnName('breakpoint'),
303 1
                $this->castToBool(true),
304 1
                $this->castToBool(false),
305 1
                $this->quoteColumnName('version'),
306 1
                $migration->getVersion(),
307 1
                $this->quoteColumnName('start_time')
308 1
            )
309 1
        );
310
311 1
        return $this;
312
    }
313
314
    /**
315
     * @inheritDoc
316
     */
317 1
    public function resetAllBreakpoints()
318
    {
319 1
        return $this->execute(
320 1
            sprintf(
321 1
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
322 1
                $this->getSchemaTableName(),
323 1
                $this->quoteColumnName('breakpoint'),
324 1
                $this->castToBool(false),
325 1
                $this->quoteColumnName('start_time')
326 1
            )
327 1
        );
328
    }
329
330
    /**
331
     * {@inheritdoc}
332
     */
333
    public function createSchema($schemaName = 'public')
334
    {
335
        throw new BadMethodCallException('Creating a schema is not supported');
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function dropSchema($name)
342
    {
343
        throw new BadMethodCallException('Dropping a schema is not supported');
344
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349 208
    public function getColumnTypes()
350
    {
351
        return [
352 208
            'string',
353 208
            'char',
354 208
            'text',
355 208
            'integer',
356 208
            'biginteger',
357 208
            'float',
358 208
            'decimal',
359 208
            'datetime',
360 208
            'timestamp',
361 208
            'time',
362 208
            'date',
363 208
            'blob',
364 208
            'binary',
365 208
            'varbinary',
366 208
            'boolean',
367 208
            'uuid',
368
            // Geospatial data types
369 208
            'geometry',
370 208
            'point',
371 208
            'linestring',
372 208
            'polygon',
373 208
        ];
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379 121
    public function castToBool($value)
380
    {
381 121
        return (bool) $value ? 1 : 0;
382
    }
383
384
    /**
385
     * Get the defintion for a `DEFAULT` statement.
386
     *
387
     * @param  mixed $default
388
     * @return string
389
     */
390
    protected function getDefaultValueDefinition($default)
391
    {
392
        if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
393
            $default = $this->getConnection()->quote($default);
394
        } elseif (is_bool($default)) {
395
            $default = $this->castToBool($default);
396
        }
397
        return isset($default) ? " DEFAULT $default" : '';
398
    }
399
}
400