Completed
Push — master ( a67fbf...bd980a )
by Nazar
04:05
created

SQLite::q_internal()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.0987

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 5
nop 2
dl 0
loc 18
ccs 11
cts 17
cp 0.6471
crap 6.0987
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\DB;
9
use
10
	SQLite3Result;
11
12
class SQLite extends _Abstract {
13
	/**
14
	 * @var \SQLite3 Instance of DB connection
15
	 */
16
	protected $instance;
17
	/**
18
	 * @param string $database Ignored for SQLite
19
	 * @param string $user     Ignored for SQLite
20
	 * @param string $password Ignored for SQLite
21
	 * @param string $host     Path to database file, relatively to website root or absolute
22
	 * @param string $prefix
23
	 */
24 24
	public function __construct ($database, $user = '', $password = '', $host = '', $prefix = '') {
25
		// Hack for HHVM: https://github.com/facebook/hhvm/issues/7225
26 24
		if (!$host) {
27 1
			return;
28
		}
29 24
		$start = microtime(true);
30
		try {
31 24
			$this->instance        = new \SQLite3($host);
32 24
			$this->database        = $database;
33 24
			$this->connected       = true;
34 24
			$this->connecting_time = microtime(true) - $start;
35 24
			$this->db_type         = 'sqlite';
36 24
			$this->prefix          = $prefix;
37
		} catch (\Exception $e) {
38
		}
39 24
	}
40
	/**
41
	 * @inheritdoc
42
	 */
43 24
	public function q ($query, ...$params) {
44 24
		return parent::q(
45 24
			$this->convert_sql($query),
46 24
			...$params
47
		);
48
	}
49
	/**
50
	 * Convert small subset of MySQL queries into SQLite-compatible syntax
51
	 *
52
	 * @param string $query
53
	 *
54
	 * @return string
55
	 */
56 24
	protected function convert_sql ($query) {
57 24
		return str_replace('INSERT IGNORE', 'INSERT OR IGNORE', $query);
58
	}
59
	/**
60
	 * @inheritdoc
61
	 *
62
	 * @return false|SQLite3Result
63
	 */
64 24
	protected function q_internal ($query, $parameters = []) {
65 24
		if (!$query) {
66 1
			return false;
67
		}
68 24
		if ($parameters) {
69 21
			$stmt = $this->instance->prepare($query);
70 21
			if (!$stmt) {
71
				return false;
72
			}
73
			// Allows to provide more parameters for prepared statements than needed
74 21
			$local_parameters = array_slice($parameters, 0, substr_count($query, '?'));
75 21
			foreach ($local_parameters as $index => $parameter) {
76 21
				$stmt->bindValue($index + 1, $parameter);
77
			}
78 21
			return $stmt->execute();
79
		}
80 24
		return $this->instance->query($query);
81
	}
82
	/**
83
	 * @inheritdoc
84
	 *
85
	 * @param false|SQLite3Result $query_result
86
	 */
87 23
	public function f ($query_result, $single_column = false, $array = false, $indexed = false) {
88 23
		if (!($query_result instanceof SQLite3Result)) {
89 1
			return false;
90
		}
91 23
		$result_type = $single_column || $indexed ? SQLITE3_NUM : SQLITE3_ASSOC;
92 23
		if ($array) {
93 20
			$result = [];
94 20
			while ($current = $query_result->fetchArray($result_type)) {
95 20
				$result[] = $single_column ? $current[0] : $current;
96
			}
97 20
			$this->free($query_result);
98 20
			return $result;
99
		}
100 22
		$result = $query_result->fetchArray($result_type);
101 22
		return $single_column && $result ? $result[0] : $result;
102
	}
103
	/**
104
	 * @inheritdoc
105
	 */
106 17
	public function id () {
107 17
		return $this->instance->lastInsertRowID();
108
	}
109
	/**
110
	 * @inheritdoc
111
	 */
112 1
	public function affected () {
113 1
		return $this->instance->changes();
114
	}
115
	/**
116
	 * @inheritdoc
117
	 *
118
	 * @param false|SQLite3Result $query_result
119
	 */
120 20
	public function free ($query_result) {
121 20
		if ($query_result instanceof SQLite3Result) {
122 20
			return $query_result->finalize();
123
		}
124 1
		return true;
125
	}
126
	/**
127
	 * @inheritdoc
128
	 */
129 2
	public function columns ($table, $like = false) {
130 2
		if (!$table) {
131 1
			return false;
132
		}
133 2
		$columns = $this->qfa("PRAGMA table_info(`$table`)") ?: [];
134 2
		foreach ($columns as &$column) {
135 2
			$column = $column['name'];
136
		}
137
		/**
138
		 * Only support the most common cases
139
		 */
140 2
		if ($like) {
141 1
			if (substr($like, -1) == '%') {
142 1
				$like = substr($like, 0, -1);
143 1
				return array_values(
144
					array_filter(
145
						$columns,
146 1
						function ($column) use ($like) {
147 1
							return strpos($column, $like) === 0;
148 1
						}
149
					)
150
				);
151 1
			} elseif (strpos($like, '%') === false) {
152 1
				return in_array($like, $columns) ? [$like] : [];
153
			} else {
154 1
				trigger_error("Can't get columns like $like, SQLite engine doesn't support such conditions", E_USER_WARNING);
155 1
				return [];
156
			}
157
		}
158 2
		return $columns;
159
	}
160
	/**
161
	 * @inheritdoc
162
	 */
163 1
	public function tables ($like = false) {
164 1
		if ($like) {
165 1
			$like = $this->s($like);
166 1
			return $this->qfas(
167
				"SELECT `name`
168
				FROM `sqlite_master`
169
				WHERE
170
					`type` = 'table' AND
171
					`name` != 'sqlite_sequence' AND
172 1
					`name` LIKE $like
173 1
				ORDER BY `name` ASC"
174 1
			) ?: [];
175
		} else {
176 1
			return $this->qfas(
177
				"SELECT `name`
178
				FROM `sqlite_master`
179
				WHERE
180
					`type` = 'table' AND
181
					`name` != 'sqlite_sequence'
182 1
				ORDER BY `name` ASC"
183 1
			) ?: [];
184
		}
185
	}
186
	/**
187
	 * @inheritdoc
188
	 */
189 22
	protected function s_internal ($string, $single_quotes_around) {
190 22
		$return = \SQLite3::escapeString($string);
191 22
		return $single_quotes_around ? "'$return'" : $return;
192
	}
193
	/**
194
	 * @inheritdoc
195
	 */
196 1
	public function server () {
197 1
		return \SQLite3::version()['versionString'];
198
	}
199
	/**
200
	 * @inheritdoc
201
	 */
202 2
	public function __destruct () {
203 2
		if ($this->connected && is_object($this->instance)) {
204 2
			$this->instance->close();
205 2
			$this->connected = false;
206
		}
207 2
	}
208
}
209