Passed
Push — master ( 380864...509b8c )
by Richard
01:39
created

SqliteAdapter   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 114
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 114
rs 10
c 0
b 0
f 0
wmc 22

11 Methods

Rating   Name   Duplication   Size   Complexity  
A alterDatabase() 0 14 1
A addIndex() 0 15 4
A getColumns() 0 7 2
A query() 0 14 4
A __construct() 0 6 1
A quote() 0 2 1
A optimiseColumns() 0 1 1
A lastInsertId() 0 2 1
A alterColumns() 0 7 3
A copyTableData() 0 11 3
A tableExists() 0 3 1
1
<?php
2
namespace Maphper\DataSource;
3
4
class SqliteAdapter implements DatabaseAdapter {
5
	private $pdo;
6
	private $stmtCache;
7
    private $generalEditor;
8
9
	public function __construct(\PDO $pdo) {
10
		$this->pdo = $pdo;
11
        $this->stmtCache = new StmtCache($pdo);
12
        $this->generalEditor = new GeneralEditDatabase($this->pdo, [
13
            'int' => 'INTEGER',
14
            'pk_default' => 'INTEGER NOT NULL',
15
        ]);
16
	}
17
18
	public function quote($str) {
19
		return $this->generalEditor->quote($str);
20
	}
21
22
	public function query(\Maphper\Lib\Query $query) {
23
        $stmt = $this->stmtCache->getCachedStmt($query->getSql());
24
		$args = $query->getArgs();
25
26
        //Handle SQLite when PDO_ERRMODE is set to SILENT
27
        if ($stmt === false) throw new \Exception('Invalid query');
28
29
        $stmt->execute($args);
30
        if ($stmt->errorCode() !== '00000' && $stmt->errorInfo()[2] == 'database schema has changed') {
31
			$this->stmtCache->deleteQueryFromCache($query->getSql());
32
			return $this->query($query);
33
        }
34
35
        return $stmt;
36
	}
37
38
	public function lastInsertId() {
39
		return $this->pdo->lastInsertId();
40
	}
41
42
	private function tableExists($name) {
43
		$result = $this->pdo->query('SELECT name FROM sqlite_master WHERE type="table" and name="'. $name.'"');
44
		return count($result->fetchAll()) == 1;
45
	}
46
47
	private function getColumns($table) {
48
		$result = $this->pdo->query('PRAGMA table_info(' . $table . ');')->fetchAll(\PDO::FETCH_OBJ);
49
		$return = [];
50
		foreach ($result as $row) {
51
			$return[] = $row->name;
52
		}
53
		return $return;
54
	}
55
56
	//Alter the database so that it can store $data
57
	public function alterDatabase($table, array $primaryKey, $data) {
58
		//Unset query cache, otherwise it causes:
59
		// SQLSTATE[HY000]: General error: 17 database schema has changed
60
		$this->stmtCache->clearCache();
61
62
        // Create temp table to create a new structure
63
		$affix = '_'.substr(md5($table), 0, 6);
64
        $tempTable = $table . $affix;
65
		$this->generalEditor->createTable($tempTable, $primaryKey, $data);
66
        $this->alterColumns($tempTable, $primaryKey, $data);
67
		$this->copyTableData($table, $tempTable);
68
69
		$this->pdo->query('DROP TABLE IF EXISTS ' . $table );
70
		$this->pdo->query('ALTER TABLE ' . $tempTable . ' RENAME TO '. $table );
71
72
	}
73
74
    private function copyTableData($tableFrom, $tableTo) {
75
        try {
76
			if ($this->tableExists($tableFrom)) {
77
				$columns = implode(', ', $this->getColumns($tableFrom));
78
79
				$this->pdo->query('INSERT INTO ' . $this->quote($tableTo) . '(' . $columns . ') SELECT ' . $columns . ' FROM ' . $this->quote($tableFrom));
80
			}
81
		}
82
		catch (\PDOException $e) {
83
			// No data to copy
84
			echo $e->getMessage();
85
		}
86
    }
87
88
    private function alterColumns($table, array $primaryKey, $data) {
89
        foreach ($data as $key => $value) {
90
			if ($this->generalEditor->isNotSavableType($value, $key, $primaryKey)) continue;
91
92
			$type = $this->generalEditor->getType($value);
93
94
			$this->pdo->query('ALTER TABLE ' . $table . ' ADD ' . $this->quote($key) . ' ' . $type);
95
		}
96
    }
97
98
    public function addIndex($table, array $fields) {
99
		if (empty($fields)) return false;
100
101
		//SQLite doesn't support ASC/DESC indexes, remove the keywords
102
		foreach ($fields as &$field) $field = str_ireplace([' desc', ' asc'], '', $field);
103
		sort($fields);
104
		$fields = array_map('strtolower', $fields);
105
		$fields = array_map('trim', $fields);
106
		$keyName = implode('_', $fields);
107
108
109
		try {
110
			$this->pdo->query('CREATE INDEX IF NOT EXISTS  ' . $keyName . ' ON ' . $table . ' (' . implode(', ', $fields) . ')');
111
		}
112
		catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
113
114
		}
115
	}
116
117
	public function optimiseColumns($table) {
118
		//TODO
119
	}
120
}
121