1
|
|
|
<?php |
2
|
|
|
namespace Maphper\DataSource; |
3
|
|
|
class MysqlAdapter implements DatabaseAdapter { |
4
|
|
|
private $pdo; |
5
|
|
|
private $queryCache = []; |
6
|
|
|
|
7
|
|
|
public function __construct(\PDO $pdo) { |
8
|
|
|
$this->pdo = $pdo; |
9
|
|
|
//Set to strict mode to detect 'out of range' errors, action at a distance but it needs to be set for all INSERT queries |
10
|
|
|
$this->pdo->query('SET sql_mode = STRICT_ALL_TABLES'); |
11
|
|
|
} |
12
|
|
|
|
13
|
|
|
public function quote($str) { |
14
|
|
|
return '`' . str_replace('.', '`.`', trim($str, '`')) . '`'; |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
private function getCachedStmt($sql) { |
18
|
|
|
$queryId = md5($sql); |
19
|
|
View Code Duplication |
if (isset($this->queryCache[$queryId])) $stmt = $this->queryCache[$queryId]; |
|
|
|
|
20
|
|
|
else { |
21
|
|
|
$stmt = $this->pdo->prepare($sql, [\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY]); |
22
|
|
|
if ($stmt) $this->queryCache[$queryId] = $stmt; |
23
|
|
|
} |
24
|
|
|
return $stmt; |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
public function query(\Maphper\Lib\Query $query) { |
28
|
|
|
$stmt = $this->getCachedStmt($query->getSql()); |
29
|
|
|
$args = $query->getArgs(); |
30
|
|
|
foreach ($args as $name => &$arg) { |
31
|
|
|
if ($arg instanceof \DateTime) $arg = $arg->format('Y-m-d H:i:s'); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
$res = $stmt->execute($args); |
|
|
|
|
35
|
|
|
|
36
|
|
|
if (strpos(trim($query->getSql()), 'SELECT') === 0) return $stmt->fetchAll(\PDO::FETCH_OBJ); |
37
|
|
|
else return $stmt; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
private function getType($val) { |
41
|
|
View Code Duplication |
if ($val instanceof \DateTime) return 'DATETIME'; |
|
|
|
|
42
|
|
|
else if (is_int($val)) return 'INT(11)'; |
43
|
|
|
else if (is_double($val)) return 'DECIMAL(9,' . strlen($val) - strrpos($val, '.') - 1 . ')'; |
44
|
|
|
else if (is_string($val)) return strlen($val) < 192 ? 'VARCHAR(191)' : 'LONGBLOB'; |
45
|
|
|
return 'VARCHAR(191)'; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
//Alter the database so that it can store $data |
49
|
|
|
private function createTable($table, array $primaryKey, $data) { |
50
|
|
|
$parts = []; |
51
|
|
View Code Duplication |
foreach ($primaryKey as $key) { |
|
|
|
|
52
|
|
|
$pk = $data->$key; |
53
|
|
|
if ($pk == null) $parts[] = $key . ' INT(11) NOT NULL AUTO_INCREMENT'; |
54
|
|
|
else $parts[] = $key . ' ' . $this->getType($pk) . ' NOT NULL'; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
$pkField = implode(', ', $parts) . ', PRIMARY KEY(' . implode(', ', $primaryKey) . ')'; |
58
|
|
|
$this->pdo->query('CREATE TABLE IF NOT EXISTS ' . $table . ' (' . $pkField . ')'); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
public function alterDatabase($table, array $primaryKey, $data) { |
62
|
|
|
$this->createTable($table, $primaryKey, $data); |
63
|
|
|
|
64
|
|
|
foreach ($data as $key => $value) { |
65
|
|
|
if (is_array($value) || (is_object($value) && !($value instanceof \DateTime))) continue; |
66
|
|
|
if (in_array($key, $primaryKey)) continue; |
67
|
|
|
|
68
|
|
|
$type = $this->getType($value); |
69
|
|
|
|
70
|
|
|
try { |
71
|
|
|
if (!$this->pdo->query('ALTER TABLE ' . $table . ' ADD ' . $this->quote($key) . ' ' . $type)) throw new \Exception('Could not alter table'); |
72
|
|
|
} |
73
|
|
|
catch (\Exception $e) { |
74
|
|
|
$this->pdo->query('ALTER TABLE ' . $table . ' MODIFY ' . $this->quote($key) . ' ' . $type); |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
public function lastInsertId() { |
80
|
|
|
return $this->pdo->lastInsertId(); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
public function addIndex($table, array $fields) { |
84
|
|
|
//Sort the fields so that the index is never created twice (col1, col2) then (col2, col1) |
85
|
|
|
sort($fields); |
86
|
|
|
$fields = array_map('strtolower', $fields); |
87
|
|
|
$fields = array_map('trim', $fields); |
88
|
|
|
$keyName = $this->quote(implode('_', $fields)); |
89
|
|
|
|
90
|
|
|
$results = $this->pdo->query('SHOW INDEX FROM ' . $this->quote($table) . ' WHERE Key_Name = "' . $keyName . '"'); |
91
|
|
|
if ($results && count($results->fetchAll()) == 0) $this->pdo->query('CREATE INDEX ' . $keyName . ' ON ' . $this->quote($table) . ' (' . implode(', ', $fields) . ')'); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
public function optimiseColumns($table) { |
95
|
|
|
//TODO |
96
|
|
|
return; |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.