Completed
Push — master ( 9e3f76...51d53f )
by Hamish
10:45
created

DBConnector::escapeIdentifier()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
DBConnector::query() 0 1 ?
1
<?php
2
3
/**
4
 * Represents an object responsible for wrapping DB connector api
5
 *
6
 * @package framework
7
 * @subpackage model
8
 */
9
abstract class DBConnector {
10
11
	/**
12
	 * List of operations to treat as write
13
	 * Implicitly includes all ddl_operations
14
	 *
15
	 * @config
16
	 * @var array
17
	 */
18
	private static $write_operations = array('insert', 'update', 'delete', 'replace');
19
20
	/**
21
	 * List of operations to treat as DDL
22
	 *
23
	 * @config
24
	 * @var array
25
	 */
26
	private static $ddl_operations = array('alter', 'drop', 'create', 'truncate');
27
28
	/**
29
	 * Error handler for database errors.
30
	 * All database errors will call this function to report the error.  It isn't a static function;
31
	 * it will be called on the object itself and as such can be overridden in a subclass.
32
	 * Subclasses should run all errors through this function.
33
	 *
34
	 * @todo hook this into a more well-structured error handling system.
35
	 * @param string $msg The error message.
36
	 * @param integer $errorLevel The level of the error to throw.
37
	 * @param string $sql The SQL related to this query
38
	 * @param array $parameters Parameters passed to the query
39
	 * @throws SS_DatabaseException
40
	 */
41
	protected function databaseError($msg, $errorLevel = E_USER_ERROR, $sql = null, $parameters = array()) {
42
		// Prevent errors when error checking is set at zero level
43
		if(empty($errorLevel)) return;
44
45
		// Format query if given
46
		if (!empty($sql)) {
47
			$formatter = new SQLFormatter();
48
			$formattedSQL = $formatter->formatPlain($sql);
49
			$msg = "Couldn't run query:\n\n{$formattedSQL}\n\n{$msg}";
50
		}
51
52
		if($errorLevel === E_USER_ERROR) {
53
			// Treating errors as exceptions better allows for responding to errors
54
			// in code, such as credential checking during installation
55
			throw new SS_DatabaseException($msg, 0, null, $sql, $parameters);
56
		} else {
57
			user_error($msg, $errorLevel);
58
		}
59
	}
60
61
	/**
62
	 * Determine if this SQL statement is a destructive operation (write or ddl)
63
	 *
64
	 * @param string $sql
65
	 * @return bool
66
	 */
67
	public function isQueryMutable($sql) {
68
		$operations = array_merge(
69
			Config::inst()->get(get_class($this), 'write_operations'),
70
			Config::inst()->get(get_class($this), 'ddl_operations')
71
		);
72
		return $this->isQueryType($sql, $operations);
73
	}
74
75
	/**
76
	 * Determine if this SQL statement is a DDL operation
77
	 *
78
	 * @param string $sql
79
	 * @return bool
80
	 */
81
	public function isQueryDDL($sql) {
82
		$operations = Config::inst()->get(get_class($this), 'ddl_operations');
83
		return $this->isQueryType($sql, $operations);
84
	}
85
86
	/**
87
	 * Determine if this SQL statement is a write operation
88
	 * (alters content but not structure)
89
	 *
90
	 * @param string $sql
91
	 * @return bool
92
	 */
93
	public function isQueryWrite($sql) {
94
		$operations = Config::inst()->get(get_class($this), 'write_operations');
95
		return $this->isQueryType($sql, $operations);
96
	}
97
98
	/**
99
	 * Determine if a query is of the given type
100
	 *
101
	 * @param string $sql Raw SQL
102
	 * @param string|array $type Type or list of types (first word in the query). Must be lowercase
103
	 */
104
	protected function isQueryType($sql, $type) {
105
		if(!preg_match('/^(?<operation>\w+)\b/', $sql, $matches)) {
106
			return false;
107
		}
108
		$operation = $matches['operation'];
109
		if(is_array($type)) {
110
			return in_array(strtolower($operation), $type);
111
		} else {
112
			return strcasecmp($sql, $type) === 0;
113
		}
114
	}
115
116
	/**
117
	 * Extracts only the parameter values for error reporting
118
	 *
119
	 * @param array $parameters
120
	 * @return array List of parameter values
121
	 */
122
	protected function parameterValues($parameters) {
123
		$values = array();
124
		foreach($parameters as $value) {
125
			$values[] = is_array($value) ? $value['value'] : $value;
126
		}
127
		return $values;
128
	}
129
130
	/**
131
	 * Link this connector to the database given the specified parameters
132
	 * Will throw an exception rather than return a success state.
133
	 * The connector should not select the database once connected until
134
	 * explicitly called by selectDatabase()
135
	 *
136
	 * @param array $parameters List of parameters such as
137
	 * <ul>
138
	 *   <li>type</li>
139
	 *   <li>server</li>
140
	 *   <li>username</li>
141
	 *   <li>password</li>
142
	 *   <li>database</li>
143
	 *   <li>path</li>
144
	 * </ul>
145
	 * @param boolean $selectDB By default database selection should be
146
	 * handled by the database controller (to enable database creation on the
147
	 * fly if necessary), but some interfaces require that the database is
148
	 * specified during connection (SQLite, Azure, etc).
149
	 */
150
	abstract public function connect($parameters, $selectDB = false);
151
152
	/**
153
	 * Query for the version of the currently connected database
154
	 *
155
	 * @return string Version of this database
156
	 */
157
	abstract public function getVersion();
158
159
	/**
160
	 * Given a value escape this for use in a query for the current database
161
	 * connector. Note that this does not quote the value.
162
	 *
163
	 * @param string $value The value to be escaped
164
	 * @return string The appropritaely escaped string for value
165
	 */
166
	abstract public function escapeString($value);
167
168
	/**
169
	 * Given a value escape and quote this appropriately for the current
170
	 * database connector.
171
	 *
172
	 * @param string $value The value to be injected into a query
173
	 * @return string The appropriately escaped and quoted string for $value
174
	 */
175
	abstract public function quoteString($value);
176
177
	/**
178
	 * Executes the following query with the specified error level.
179
	 * Implementations of this function should respect previewWrite and benchmarkQuery
180
	 *
181
	 * @see http://php.net/manual/en/errorfunc.constants.php
182
	 * @param string $sql The SQL query to execute
183
	 * @param integer $errorLevel For errors to this query, raise PHP errors
184
	 * using this error level.
185
	 */
186
	abstract public function query($sql, $errorLevel = E_USER_ERROR);
187
188
	/**
189
	 * Execute the given SQL parameterised query with the specified arguments
190
	 *
191
	 * @param string $sql The SQL query to execute. The ? character will denote parameters.
192
	 * @param array $parameters An ordered list of arguments.
193
	 * @param int $errorLevel The level of error reporting to enable for the query
194
	 * @return SS_Query
195
	 */
196
	abstract public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR);
197
198
	/**
199
	 * Select a database by name
200
	 *
201
	 * @param string $name Name of database
202
	 * @return boolean Flag indicating success
203
	 */
204
	abstract public function selectDatabase($name);
205
206
	/**
207
	 * Retrieves the name of the currently selected database
208
	 *
209
	 * @return string Name of the database, or null if none selected
210
	 */
211
	abstract public function getSelectedDatabase();
212
213
	/**
214
	 * De-selects the currently selected database
215
	 */
216
	abstract public function unloadDatabase();
217
218
	/**
219
	 * Retrieves the last error generated from the database connection
220
	 *
221
	 * @return string The error message
222
	 */
223
	abstract public function getLastError();
224
225
	/**
226
	 * Determines the last ID generated from the specified table.
227
	 * Note that some connectors may not be able to return $table specific responses,
228
	 * and this parameter may be ignored.
229
	 *
230
	 * @param string $table The target table to return the last generated ID for
231
	 * @return integer ID value
232
	 */
233
	abstract public function getGeneratedID($table);
234
235
	/**
236
	 * Determines the number of affected rows from the last SQL query
237
	 *
238
	 * @return integer Number of affected rows
239
	 */
240
	abstract public function affectedRows();
241
242
	/**
243
	 * Determines if we are connected to a server AND have a valid database
244
	 * selected.
245
	 *
246
	 * @return boolean Flag indicating that a valid database is connected
247
	 */
248
	abstract public function isActive();
249
}
250