Passed
Push — master ( 53adaa...8a2369 )
by Tom
02:01
created

MysqlAdapter::alterDatabase()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 9
nc 6
nop 3
dl 0
loc 14
rs 7.7777
c 0
b 0
f 0
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];
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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);
0 ignored issues
show
Unused Code introduced by
The assignment to $res is dead and can be removed.
Loading history...
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';
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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