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

SQLite   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 64.65%

Importance

Changes 0
Metric Value
dl 0
loc 197
ccs 86
cts 133
cp 0.6465
rs 8.2769
c 0
b 0
f 0
wmc 41
lcom 1
cbo 1

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
A q() 0 6 1
A convert_sql() 0 3 1
B q_internal() 0 18 5
B f() 0 16 9
A id() 0 3 1
A affected() 0 3 1
A free() 0 6 2
C columns() 0 31 8
B tables() 0 23 4
A s_internal() 0 4 2
A server() 0 3 1
A __destruct() 0 6 3

How to fix   Complexity   

Complex Class

Complex classes like SQLite often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SQLite, and based on these observations, apply Extract Interface, too.

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