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

PdoAdapter::getConnection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
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
        $columns = array_keys($row);
182
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ')';
183 1
        
184 1
        if ($this->isDryRunEnabled()) {
185 1
            
186
            $sql .= ' VALUES (' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ');';
187
            $this->output->writeln($sql);
188
            
189
        } else {
190 11
191
            $sql .= ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
192 11
            $stmt = $this->getConnection()->prepare($sql);
193 11
            $stmt->execute(array_values($row));
194 11
            
195 11
        }
196
    }
197 11
198 11
    /**
199 11
     * Quotes a database value.
200
     *
201 11
     * @param mixed $value  The value to quote
202 11
     * @return mixed
203 11
     */
204 11
    private function quoteValue($value)
205 11
    {
206 11
        if (is_numeric($value)) {
207
            return $value;
208 11
        }
209 11
210
        if ($value === null) {
211 11
            return 'null';
212 11
        }
213 11
214
        return $this->getConnection()->quote($value);
215 11
    }
216 11
217 11
    /**
218
     * {@inheritdoc}
219
     */
220
    public function bulkinsert(Table $table, $rows)
221
    {
222 5
        $sql = sprintf(
223
            'INSERT INTO %s ',
224 5
            $this->quoteTableName($table->getName())
225
        );
226 5
        $current = current($rows);
227
        $keys = array_keys($current);
228
        $sql .= '(' . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ') VALUES ';
229
        
230
        if ($this->isDryRunEnabled()) {
231
            
232 8
            $values = array_map(function ($row) {
233
                return '(' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ')';
234 8
            }, $rows);
235
            $sql .= implode(', ', $values) . ';';
236 8
            $this->output->writeln($sql);
237 8
            
238 6
        } else {
239 6
240 2
            $count_keys = count($keys);
241 1
            $query = '(' . implode(', ', array_fill(0, $count_keys, '?')) . ')';
242 1
            $count_vars = count($rows);
243 1
            $queries = array_fill(0, $count_vars, $query);
244 1
            $sql .= implode(',', $queries);
245 8
            $stmt = $this->getConnection()->prepare($sql);
246
            $vals = [];
247 7
            
248 7
            foreach ($rows as $row) {
249 7
                foreach ($row as $v) {
250 7
                    $vals[] = $v;
251
                }
252 7
            }
253
            
254
            $stmt->execute($vals);
255
            
256
        }
257
    }
258 5
259
    /**
260 5
     * {@inheritdoc}
261
     */
262 5
    public function getVersions()
263 5
    {
264 5
        $rows = $this->getVersionLog();
265 5
266 5
        return array_keys($rows);
267 5
    }
268 5
269 5
    /**
270 5
     * {@inheritdoc}
271 5
     */
272 5
    public function getVersionLog()
273 5
    {
274 5
        $result = [];
275 5
276
        switch ($this->options['version_order']) {
277 5
            case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
278 5
                $orderBy = 'version ASC';
279
                break;
280 3
            case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
281 3
                $orderBy = 'start_time ASC, version ASC';
282 3
                break;
283 3
            default:
284 3
                throw new \RuntimeException('Invalid version_order configuration option');
285 3
        }
286
287 3
        $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->getSchemaTableName(), $orderBy));
288
        foreach ($rows as $version) {
289
            $result[$version['version']] = $version;
290 5
        }
291
292
        return $result;
293
    }
294
295
    /**
296 1
     * {@inheritdoc}
297
     */
298 1
    public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
299 1
    {
300 1
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
301 1
            // up
302 1
            $sql = sprintf(
303 1
                "INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
304 1
                $this->getSchemaTableName(),
305 1
                $this->quoteColumnName('version'),
306 1
                $this->quoteColumnName('migration_name'),
307 1
                $this->quoteColumnName('start_time'),
308 1
                $this->quoteColumnName('end_time'),
309 1
                $this->quoteColumnName('breakpoint'),
310
                $migration->getVersion(),
311 1
                substr($migration->getName(), 0, 100),
312
                $startTime,
313
                $endTime,
314
                $this->castToBool(false)
315
            );
316
317 1
            $this->execute($sql);
318
        } else {
319 1
            // down
320 1
            $sql = sprintf(
321 1
                "DELETE FROM %s WHERE %s = '%s'",
322 1
                $this->getSchemaTableName(),
323 1
                $this->quoteColumnName('version'),
324 1
                $migration->getVersion()
325 1
            );
326 1
327 1
            $this->execute($sql);
328
        }
329
330
        return $this;
331
    }
332
333
    /**
334
     * @inheritDoc
335
     */
336
    public function toggleBreakpoint(MigrationInterface $migration)
337
    {
338
        $this->query(
339
            sprintf(
340
                '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\';',
341
                $this->getSchemaTableName(),
342
                $this->quoteColumnName('breakpoint'),
343
                $this->castToBool(true),
344
                $this->castToBool(false),
345
                $this->quoteColumnName('version'),
346
                $migration->getVersion(),
347
                $this->quoteColumnName('start_time')
348
            )
349 208
        );
350
351
        return $this;
352 208
    }
353 208
354 208
    /**
355 208
     * @inheritDoc
356 208
     */
357 208
    public function resetAllBreakpoints()
358 208
    {
359 208
        return $this->execute(
360 208
            sprintf(
361 208
                'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
362 208
                $this->getSchemaTableName(),
363 208
                $this->quoteColumnName('breakpoint'),
364 208
                $this->castToBool(false),
365 208
                $this->quoteColumnName('start_time')
366 208
            )
367 208
        );
368
    }
369 208
370 208
    /**
371 208
     * {@inheritdoc}
372 208
     */
373 208
    public function createSchema($schemaName = 'public')
374
    {
375
        throw new BadMethodCallException('Creating a schema is not supported');
376
    }
377
378
    /**
379 121
     * {@inheritdoc}
380
     */
381 121
    public function dropSchema($name)
382
    {
383
        throw new BadMethodCallException('Dropping a schema is not supported');
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389
    public function getColumnTypes()
390
    {
391
        return [
392
            'string',
393
            'char',
394
            'text',
395
            'integer',
396
            'biginteger',
397
            'float',
398
            'decimal',
399
            'datetime',
400
            'timestamp',
401
            'time',
402
            'date',
403
            'blob',
404
            'binary',
405
            'varbinary',
406
            'boolean',
407
            'uuid',
408
            // Geospatial data types
409
            'geometry',
410
            'point',
411
            'linestring',
412
            'polygon',
413
        ];
414
    }
415
416
    /**
417
     * {@inheritdoc}
418
     */
419
    public function castToBool($value)
420
    {
421
        return (bool)$value ? 1 : 0;
422
    }
423
}
424