Completed
Pull Request — master (#1175)
by David Joseph
01:44
created

PdoAdapter::createSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
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\Migration\MigrationInterface;
34
35
/**
36
 * Phinx PDO Adapter.
37
 *
38
 * @author Rob Morgan <[email protected]>
39
 */
40
abstract class PdoAdapter extends AbstractAdapter
41
{
42
    /**
43
     * @var \PDO|null
44
     */
45
    protected $connection;
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function setOptions(array $options)
51 287
    {
52
        parent::setOptions($options);
53 287
54
        if (isset($options['connection'])) {
55 287
            $this->setConnection($options['connection']);
56 3
        }
57 3
58
        return $this;
59 287
    }
60
61
    /**
62
     * Sets the database connection.
63
     *
64
     * @param \PDO $connection Connection
65
     * @return \Phinx\Db\Adapter\AdapterInterface
66
     */
67
    public function setConnection(\PDO $connection)
68 193
    {
69
        $this->connection = $connection;
70 193
71
        // Create the schema table if it doesn't already exist
72
        if (!$this->hasSchemaTable()) {
73 193
            $this->createSchemaTable();
74 191
        } else {
75 191
            $table = new Table($this->getSchemaTableName(), [], $this);
76 74
            if (!$table->hasColumn('migration_name')) {
77 74
                $table
78
                    ->addColumn(
79
                        'migration_name',
80
                        'string',
81
                        ['limit' => 100, 'after' => 'version', 'default' => null, 'null' => true]
82
                    )
83
                    ->save();
84
            }
85
            if (!$table->hasColumn('breakpoint')) {
86 74
                $table
87
                    ->addColumn('breakpoint', 'boolean', ['default' => false])
88
                    ->save();
89
            }
90
        }
91
92
        return $this;
93 193
    }
94
95
    /**
96
     * Gets the database connection
97
     *
98
     * @return \PDO
99
     */
100
    public function getConnection()
101 191
    {
102
        if ($this->connection === null) {
103 191
            $this->connect();
104 189
        }
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
131
            return 0;
132
        }
133 217
134
        return $this->getConnection()->exec($sql);
135
    }
136
137
    /**
138
     * Executes a query and returns PDOStatement.
139
     *
140
     * @param string $sql SQL
141
     * @return \PDOStatement
142 220
     */
143
    public function query($sql)
144 220
    {
145
        return $this->getConnection()->query($sql);
146
    }
147
148
    /**
149
     * {@inheritdoc}
150 151
     */
151
    public function fetchRow($sql)
152 151
    {
153 151
        $result = $this->query($sql);
154
155
        return $result->fetch();
156
    }
157
158
    /**
159 213
     * {@inheritdoc}
160
     */
161 213
    public function fetchAll($sql)
162 213
    {
163 213
        $rows = [];
164 208
        $result = $this->query($sql);
165 208
        while ($row = $result->fetch()) {
166 213
            $rows[] = $row;
167
        }
168
169
        return $rows;
170
    }
171
172 1
    /**
173
     * {@inheritdoc}
174 1
     */
175 1
    public function insert(Table $table, $row)
176 1
    {
177 1
        $sql = sprintf(
178
            "INSERT INTO %s ",
179 1
            $this->quoteTableName($table->getName())
180 1
        );
181 1
182
        $columns = array_keys($row);
183 1
        $sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ")";
184 1
        $sql .= " VALUES (" . implode(', ', array_fill(0, count($columns), '?')) . ")";
185 1
186
        $stmt = $this->getConnection()->prepare($sql);
187
        $stmt->execute(array_values($row));
188
    }
189
190 11
    /**
191
     * {@inheritdoc}
192 11
     */
193 11
    public function bulkinsert(Table $table, $rows)
194 11
    {
195 11
        $sql = sprintf(
196
            "INSERT INTO %s ",
197 11
            $this->quoteTableName($table->getName())
198 11
        );
199 11
200
        $current = current($rows);
201 11
        $keys = array_keys($current);
202 11
        $sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ") VALUES";
203 11
204 11
        $vals = [];
205 11
        foreach ($rows as $row) {
206 11
            foreach ($row as $v) {
207
                $vals[] = $v;
208 11
            }
209 11
        }
210
211 11
        $count_keys = count($keys);
212 11
        $query = "(" . implode(', ', array_fill(0, $count_keys, '?')) . ")";
213 11
214
        $count_vars = count($rows);
215 11
        $queries = array_fill(0, $count_vars, $query);
216 11
        $sql .= implode(',', $queries);
217 11
218
        $stmt = $this->getConnection()->prepare($sql);
219
        $stmt->execute($vals);
220
    }
221
222 5
    /**
223
     * {@inheritdoc}
224 5
     */
225
    public function getVersions()
226 5
    {
227
        $rows = $this->getVersionLog();
228
229
        return array_keys($rows);
230
    }
231
232 8
    /**
233
     * {@inheritdoc}
234 8
     */
235
    public function getVersionLog()
236 8
    {
237 8
        $result = [];
238 6
239 6
        switch ($this->options['version_order']) {
240 2
            case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
241 1
                $orderBy = 'version ASC';
242 1
                break;
243 1
            case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
244 1
                $orderBy = 'start_time ASC, version ASC';
245 8
                break;
246
            default:
247 7
                throw new \RuntimeException('Invalid version_order configuration option');
248 7
        }
249 7
250 7
        $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->getSchemaTableName(), $orderBy));
251
        foreach ($rows as $version) {
252 7
            $result[$version['version']] = $version;
253
        }
254
255
        return $result;
256
    }
257
258 5
    /**
259
     * {@inheritdoc}
260 5
     */
261
    public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
262 5
    {
263 5
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
264 5
            // up
265 5
            $sql = sprintf(
266 5
                "INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
267 5
                $this->getSchemaTableName(),
268 5
                $this->quoteColumnName('version'),
269 5
                $this->quoteColumnName('migration_name'),
270 5
                $this->quoteColumnName('start_time'),
271 5
                $this->quoteColumnName('end_time'),
272 5
                $this->quoteColumnName('breakpoint'),
273 5
                $migration->getVersion(),
274 5
                substr($migration->getName(), 0, 100),
275 5
                $startTime,
276
                $endTime,
277 5
                $this->castToBool(false)
278 5
            );
279
280 3
            $this->execute($sql);
281 3
        } else {
282 3
            // down
283 3
            $sql = sprintf(
284 3
                "DELETE FROM %s WHERE %s = '%s'",
285 3
                $this->getSchemaTableName(),
286
                $this->quoteColumnName('version'),
287 3
                $migration->getVersion()
288
            );
289
290 5
            $this->execute($sql);
291
        }
292
293
        return $this;
294
    }
295
296 1
    /**
297
     * @inheritDoc
298 1
     */
299 1
    public function toggleBreakpoint(MigrationInterface $migration)
300 1
    {
301 1
        $this->query(
302 1
            sprintf(
303 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\';',
304 1
                $this->getSchemaTableName(),
305 1
                $this->quoteColumnName('breakpoint'),
306 1
                $this->castToBool(true),
307 1
                $this->castToBool(false),
308 1
                $this->quoteColumnName('version'),
309 1
                $migration->getVersion(),
310
                $this->quoteColumnName('start_time')
311 1
            )
312
        );
313
314
        return $this;
315
    }
316
317 1
    /**
318
     * @inheritDoc
319 1
     */
320 1
    public function resetAllBreakpoints()
321 1
    {
322 1
        return $this->execute(
323 1
            sprintf(
324 1
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
325 1
                $this->getSchemaTableName(),
326 1
                $this->quoteColumnName('breakpoint'),
327 1
                $this->castToBool(false),
328
                $this->quoteColumnName('start_time')
329
            )
330
        );
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function createSchema($schemaName = 'public')
337
    {
338
        throw new BadMethodCallException('Creating a schema is not supported');
339
    }
340
341
    /**
342
     * {@inheritdoc}
343
     */
344
    public function dropSchema($name)
345
    {
346
        throw new BadMethodCallException('Dropping a schema is not supported');
347
    }
348
349 208
    /**
350
     * {@inheritdoc}
351
     */
352 208
    public function getColumnTypes()
353 208
    {
354 208
        return [
355 208
            'string',
356 208
            'char',
357 208
            'text',
358 208
            'integer',
359 208
            'biginteger',
360 208
            'float',
361 208
            'decimal',
362 208
            'datetime',
363 208
            'timestamp',
364 208
            'time',
365 208
            'date',
366 208
            'blob',
367 208
            'binary',
368
            'varbinary',
369 208
            'boolean',
370 208
            'uuid',
371 208
            // Geospatial data types
372 208
            'geometry',
373 208
            'point',
374
            'linestring',
375
            'polygon',
376
        ];
377
    }
378
379 121
    /**
380
     * {@inheritdoc}
381 121
     */
382
    public function castToBool($value)
383
    {
384
        return (bool)$value ? 1 : 0;
385
    }
386
387
    /**
388
     * Get the defintion for a `DEFAULT` statement.
389
     *
390
     * @param  mixed $default Default value
391
     * @return string
392
     */
393
    protected function getDefaultValueDefinition($default)
394
    {
395
        if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
396
            $default = $this->getConnection()->quote($default);
397
        } elseif (is_bool($default)) {
398
            $default = $this->castToBool($default);
399
        }
400
401
        return isset($default) ? " DEFAULT $default" : '';
402
    }
403
}
404