SqlServer   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Importance

Changes 11
Bugs 0 Features 0
Metric Value
eloc 72
c 11
b 0
f 0
dl 0
loc 198
rs 10
wmc 22

7 Methods

Rating   Name   Duplication   Size   Complexity  
A queryAffected() 0 10 2
A connect() 0 23 4
A queryInsertId() 0 10 2
A error() 0 9 2
A translator() 0 7 2
B query() 0 69 8
A disconnect() 0 7 2
1
<?php
2
namespace Darya\Database\Connection;
3
4
use Darya\Database\AbstractConnection;
5
use Darya\Database\Error;
6
use Darya\Database\Query\Translator;
7
use Darya\Database\Result;
8
use Darya\Database\Query;
9
10
/**
11
 * Darya's SQL Server (MSSQL) database interface for Windows.
12
 *
13
 * @author Chris Andrew <[email protected]>
14
 */
15
class SqlServer extends AbstractConnection
16
{
17
	/**
18
	 * @var resource
19
	 */
20
	protected $connection;
21
22
	/**
23
	 * Initiate the connection.
24
	 *
25
	 * @return bool
26
	 */
27
	public function connect()
28
	{
29
		if ($this->connected()) {
30
			return true;
31
		}
32
33
		$host = $this->details['host'];
34
35
		if ($this->details['port']) {
36
			$host .= ', ' . $this->details['port'];
37
		}
38
39
		$this->connection = sqlsrv_connect($this->details['host'], array(
40
			'UID'      => $this->details['user'],
41
			'PWD'      => $this->details['pass'],
42
			'Database' => $this->details['name']
43
		));
44
45
		if ($this->error()) {
46
			return false;
47
		}
48
49
		return $this->connected = true;
50
	}
51
52
	/**
53
	 * Close the connection.
54
	 */
55
	public function disconnect()
56
	{
57
		if ($this->connected()) {
58
			sqlsrv_close($this->connection);
59
		}
60
61
		$this->connected = false;
62
	}
63
64
	/**
65
	 * Retrieve the query translator.
66
	 *
67
	 * @return Translator
68
	 */
69
	public function translator()
70
	{
71
		if (!$this->translator) {
72
			$this->translator = new Translator\SqlServer;
73
		}
74
75
		return $this->translator;
76
	}
77
78
	/**
79
	 * Query the database for the last ID generated, if the given query is
80
	 * an insert query.
81
	 *
82
	 * @param string $query
83
	 * @return int
84
	 */
85
	protected function queryInsertId($query)
86
	{
87
		if (!preg_match('/^\s*INSERT\s+INTO\b/i', $query)) {
88
			return null;
89
		}
90
91
		$result = sqlsrv_query($this->connection, "SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) as INT) id");
92
		list($id) = sqlsrv_fetch_array($result, SQLSRV_FETCH_NUMERIC);
93
94
		return $id;
95
	}
96
97
	/**
98
	 * Query the database for the number of rows affected by the last query.
99
	 *
100
	 * @param string $query
101
	 * @return int
102
	 */
103
	protected function queryAffected($query)
104
	{
105
		if (preg_match('/^\s*SELECT\b/i', $query)) {
106
			return null;
107
		}
108
109
		$result = sqlsrv_query($this->connection, "SELECT @@ROWCOUNT affected");
110
		list($affected) = sqlsrv_fetch_array($result, SQLSRV_FETCH_NUMERIC);
111
112
		return $affected;
113
	}
114
115
	/**
116
	 * Query the database.
117
	 *
118
	 * TODO: Simplify.
119
	 * TODO: Strip out row_number if present.
120
	 *
121
	 * @param Query|string $query
122
	 * @param array        $parameters [optional]
123
	 * @return Result
124
	 */
125
	public function query($query, array $parameters = array())
126
	{
127
		if (!$query instanceof Query) {
128
			$query = new Query($query, $parameters);
129
		}
130
131
		$this->lastResult = null;
132
133
		$this->connect();
134
135
		if (!$this->connected()) {
136
			$this->lastResult = new Result($query, array(), array(), $this->error());
137
138
			$this->event('sqlserver.query', array($this->lastResult));
139
140
			return $this->lastResult;
141
		}
142
143
		$this->event('sqlserver.prequery', array($query));
144
145
		$mssql_result = sqlsrv_query($this->connection, $query->string, $query->parameters, array(
146
			'Scrollable' => SQLSRV_CURSOR_CLIENT_BUFFERED
147
		));
148
149
		$result = array(
150
			'data'      => array(),
151
			'fields'    => array(),
152
			'affected'  => null,
153
			'num_rows'  => null,
154
			'insert_id' => null
155
		);
156
157
		$error = $this->error();
158
159
		if ($mssql_result === false || $error) {
0 ignored issues
show
introduced by
$error is of type Darya\Database\Error, thus it always evaluated to true.
Loading history...
160
			$this->lastResult = new Result($query, array(), array(), $error);
161
162
			$this->event('sqlserver.query', array($this->lastResult));
163
164
			return $this->lastResult;
165
		}
166
167
		$result['num_rows'] = sqlsrv_num_rows($mssql_result);
168
169
		if ($result['num_rows']) {
170
			while ($row = sqlsrv_fetch_array($mssql_result, SQLSRV_FETCH_ASSOC)) {
171
				if (!$result['fields']) {
172
					$result['fields'] = array_keys($row);
173
				}
174
175
				$result['data'][] = $row;
176
			}
177
		}
178
179
		$result['insert_id'] = $this->queryInsertId($query);
180
		$result['affected'] = $this->queryAffected($query);
181
182
		$info = array(
183
			'count'     => $result['num_rows'],
184
			'fields'    => $result['fields'],
185
			'affected'  => $result['affected'],
186
			'insert_id' => $result['insert_id']
187
		);
188
189
		$this->lastResult = new Result($query, $result['data'], $info, $error);
190
191
		$this->event('sqlserver.query', array($this->lastResult));
192
193
		return $this->lastResult;
194
	}
195
196
	/**
197
	 * Retrieve error information regarding the last query or connection
198
	 * attempt.
199
	 *
200
	 * Returns null if there is no error.
201
	 *
202
	 * @return Error
203
	 */
204
	public function error()
205
	{
206
		$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
207
208
		if (!$errors) {
209
			return null;
210
		}
211
212
		return new Error($errors[0]['code'], $errors[0]['message']);
213
	}
214
}
215