Passed
Push — master ( 66acfb...380864 )
by Richard
01:44
created

MysqlAdapter::alterDatabase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Maphper\DataSource;
3
class MysqlAdapter implements DatabaseAdapter {
4
	private $pdo;
5
	private $stmtCache;
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
        $this->stmtCache = new StmtCache($pdo);
12
	}
13
14
	public function quote($str) {
15
		return '`' . str_replace('.', '`.`', trim($str, '`')) . '`';
16
	}
17
18
	public function query(\Maphper\Lib\Query $query) {
19
		$stmt = $this->stmtCache->getCachedStmt($query->getSql());
20
		$args = $query->getArgs();
21
        $stmt->execute($args);
22
23
		return $stmt;
24
	}
25
26
	private function getType($val) {
27
		if ($val instanceof \DateTime) return 'DATETIME';
28
		else if (is_int($val)) return  'INT(11)';
29
		else if (is_double($val)) return 'DECIMAL(9,' . strlen($val) - strrpos($val, '.') - 1 . ')';
30
		else if (is_string($val)) return strlen($val) < 192 ? 'VARCHAR(191)' : 'LONGBLOB';
31
		return 'VARCHAR(191)';
32
	}
33
34
	//Alter the database so that it can store $data
35
	private function createTable($table, array $primaryKey, $data) {
36
		$parts = [];
37
		foreach ($primaryKey as $key) {
38
			$pk = $data->$key;
39
			if ($pk == null) $parts[] = $key . ' INT(11) NOT NULL AUTO_INCREMENT';
40
			else $parts[] = $key . ' ' . $this->getType($pk) . ' NOT NULL';
41
		}
42
43
		$pkField = implode(', ', $parts) . ', PRIMARY KEY(' . implode(', ', $primaryKey) . ')';
44
		$this->pdo->query('CREATE TABLE IF NOT EXISTS ' . $table . ' (' . $pkField . ')');
45
	}
46
47
    private function alterColumns($table, array $primaryKey, $data) {
48
        foreach ($data as $key => $value) {
49
			if ($this->isNotSavableType($value, $key, $primaryKey)) continue;
50
51
			$type = $this->getType($value);
52
53
			try {
54
				if (!$this->pdo->query('ALTER TABLE ' . $table . ' ADD ' . $this->quote($key) . ' ' . $type)) throw new \Exception('Could not alter table');
55
			}
56
			catch (\Exception $e) {
57
				$this->pdo->query('ALTER TABLE ' . $table . ' MODIFY ' . $this->quote($key) . ' ' . $type);
58
			}
59
		}
60
    }
61
62
    private function isNotSavableType($value, $key, $primaryKey) {
63
        return is_array($value) || (is_object($value) && !($value instanceof \DateTime)) ||
64
                in_array($key, $primaryKey);
65
    }
66
67
	public function alterDatabase($table, array $primaryKey, $data) {
68
		$this->createTable($table, $primaryKey, $data);
69
        $this->alterColumns($table, $primaryKey, $data);
70
	}
71
72
	public function lastInsertId() {
73
		return $this->pdo->lastInsertId();
74
	}
75
76
	public function addIndex($table, array $fields) {
77
		//Sort the fields so that the index is never created twice (col1, col2) then (col2, col1)
78
		sort($fields);
79
		$fields = array_map('strtolower', $fields);
80
		$fields = array_map('trim', $fields);
81
		$keyName = $this->quote(implode('_', $fields));
82
83
		$results = $this->pdo->query('SHOW INDEX FROM ' . $this->quote($table) . ' WHERE Key_Name = "' . $keyName . '"');
84
		if ($results && count($results->fetchAll()) == 0)  $this->pdo->query('CREATE INDEX ' . $keyName . ' ON ' . $this->quote($table) . ' (' . implode(', ', $fields) . ')');
85
	}
86
87
	public function optimiseColumns($table) {
88
		//TODO
89
		return;
90
	}
91
}
92