Passed
Push — master ( bffbee...0a6ac4 )
by Adrian
01:51
created

DbService::getResultType()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 17
rs 7.7777
cc 8
eloc 12
nc 8
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * Author: Adrian Dumitru
5
 * Date: 6/1/2017 4:14 PM
6
 */
7
8
namespace Qpdb\QueryBuilder\DB;
9
10
11
class DbService
12
{
13
14
	const QUERY_TYPE_INSERT = 'INSERT';
15
	const QUERY_TYPE_DELETE = 'DELETE';
16
	const QUERY_TYPE_UPDATE = 'UPDATE';
17
	const QUERY_TYPE_SELECT = 'SELECT';
18
	const QUERY_TYPE_REPLACE = 'REPLACE';
19
	const QUERY_TYPE_SHOW = 'SHOW';
20
	const QUERY_TYPE_DESC = 'DESC';
21
	const QUERY_TYPE_EMPTY = 'EMPTY';
22
	const QUERY_TYPE_OTHER = 'OTHER';
23
	const QUERY_TYPE_EXPLAIN = 'EXPLAIN';
24
25
	const ON_ERROR_THROW_EXCEPTION = 1;
26
	const ON_ERROR_RETURN_ERROR = 2;
27
28
	const QUERY_RESULT_TYPE_ARRAY = 'array';
29
	const QUERY_RESULT_TYPE_NUMBER = 'number';
30
	const QUERY_RESULT_TYPE_NULL = 'null';
31
32
	/**
33
	 * @var DbService
34
	 */
35
	private static $instance;
36
37
	/**
38
	 * @var \PDO
39
	 */
40
	private $pdo;
41
42
	/**
43
	 * @var \PDOStatement
44
	 */
45
	private $sQuery;
46
47
	/**
48
	 * @var array
49
	 */
50
	private $parameters = [];
51
52
	/**
53
	 * @var string;
54
	 */
55
	private $lastStatement;
56
57
58
	/**
59
	 * @param string $query
60
	 * @param array $params
61
	 * @param int $fetchMode
62
	 * @return array|int|null
63
	 */
64
	public function query( $query, $params = null, $fetchMode = \PDO::FETCH_ASSOC )
65
	{
66
67
		$this->queryInit( $query, $params );
68
		$resultType = $this->getResultType( $this->lastStatement );
69
70
		switch ( $resultType ) {
71
			case self::QUERY_RESULT_TYPE_ARRAY:
72
				$result = $this->sQuery->fetchAll( $fetchMode );
73
				break;
74
			case self::QUERY_RESULT_TYPE_NUMBER:
75
				$result = $this->sQuery->rowCount();
76
				break;
77
			default:
78
				$result = null;
79
				break;
80
		}
81
82
		$this->sQuery->closeCursor();
83
84
		return $result;
85
	}
86
87
	/**
88
	 * @param $query
89
	 * @param array $params
90
	 * @return array|null
91
	 */
92
	public function column( $query, $params = null )
93
	{
94
		$this->queryInit( $query, $params );
95
96
		if ( $this->lastStatement === self::QUERY_TYPE_EXPLAIN )
97
			return $this->sQuery->fetchAll( \PDO::FETCH_ASSOC );
98
99
		$Columns = $this->sQuery->fetchAll( \PDO::FETCH_NUM );
100
101
		$column = null;
102
103
		foreach ( $Columns as $cells ) {
104
			$column[] = $cells[ 0 ];
105
		}
106
107
		return $column;
108
	}
109
110
	/**
111
	 * @param string $query
112
	 * @param array $params
113
	 * @param int $fetchmode
114
	 * @return array|mixed
115
	 */
116 View Code Duplication
	public function row( $query, $params = null, $fetchmode = \PDO::FETCH_ASSOC )
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
	{
118
		$this->queryInit( $query, $params );
119
120
		if ( $this->lastStatement === self::QUERY_TYPE_EXPLAIN )
121
			return $this->sQuery->fetchAll( \PDO::FETCH_ASSOC );
122
123
		$result = $this->sQuery->fetch( $fetchmode );
124
		$this->sQuery->closeCursor(); // Frees up the connection to the server so that other SQL statements may be issued,
125
126
		return $result;
127
	}
128
129
	/**
130
	 * @param string $query
131
	 * @param array $params
132
	 * @return mixed|array
133
	 */
134 View Code Duplication
	public function single( $query, $params = null )
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
	{
136
		$this->queryInit( $query, $params );
137
138
		if ( $this->lastStatement === self::QUERY_TYPE_EXPLAIN )
139
			return $this->sQuery->fetchAll( \PDO::FETCH_ASSOC );
140
141
		$result = $this->sQuery->fetchColumn();
142
		$this->sQuery->closeCursor(); // Frees up the connection to the server so that other SQL statements may be issued
143
144
		return $result;
145
	}
146
147
148
	/**
149
	 * @param string $statement
150
	 * @return string
151
	 */
152
	private function getResultType( $statement )
153
	{
154
		switch ( $statement ) {
155
156
			case self::QUERY_TYPE_SELECT:
157
			case self::QUERY_TYPE_SHOW:
158
			case self::QUERY_TYPE_DESC:
159
			case self::QUERY_TYPE_EXPLAIN:
160
				return self::QUERY_RESULT_TYPE_ARRAY;
161
162
			case self::QUERY_TYPE_INSERT:
163
			case self::QUERY_TYPE_UPDATE:
164
			case self::QUERY_TYPE_DELETE:
165
				return self::QUERY_RESULT_TYPE_NUMBER;
166
167
			default:
168
				return self::QUERY_RESULT_TYPE_NULL;
169
170
		}
171
	}
172
173
174
	/**
175
	 * @param string $query
176
	 * @param array $parameters
177
	 * @throws DbException
178
	 */
179
	private function queryInit( $query, $parameters = [] )
180
	{
181
		$this->lastStatement = self::getQueryStatement( $query );
182
		$this->pdo = DbConnect::getInstance()->getConnection( $this->lastStatement );
183
		$startQueryTime = microtime( true );
184
185
		try {
186
187
			/**
188
			 * Prepare query
189
			 */
190
			$this->sQuery = $this->pdo->prepare( $query );
191
192
			/**
193
			 * Add parameters to the parameter array
194
			 */
195
			if ( self::isArrayAssoc( $parameters ) )
196
				$this->bindMore( $parameters );
197
			else
198
				foreach ( $parameters as $key => $val )
199
					$this->parameters[] = array( $key + 1, $val );
200
201
			if ( count( $this->parameters ) ) {
202
				foreach ( $this->parameters as $param => $value ) {
203
					if ( is_int( $value[ 1 ] ) ) {
204
						$type = \PDO::PARAM_INT;
205
					}
206
					elseif ( is_bool( $value[ 1 ] ) ) {
207
						$type = \PDO::PARAM_BOOL;
208
					}
209
					elseif ( is_null( $value[ 1 ] ) ) {
210
						$type = \PDO::PARAM_NULL;
211
					}
212
					else {
213
						$type = \PDO::PARAM_STR;
214
					}
215
					$this->sQuery->bindValue( $value[ 0 ], $value[ 1 ], $type );
216
				}
217
			}
218
219
			$this->sQuery->execute();
220
221
			if ( DbConfig::getInstance()->isEnableLogQueryDuration() ) {
222
				$duration = microtime( true ) - $startQueryTime;
223
				DbLog::getInstance()->writeQueryDuration( $query, $duration );
224
			}
225
226
		} catch ( \PDOException $e ) {
227
			if ( DbConfig::getInstance()->isEnableLogErrors() ) {
228
				DbLog::getInstance()->writeQueryErrors( $query, $e );
229
			}
230
			throw new DbException( 'Database query runtime error!', DbException::DB_QUERY_ERROR );
231
		}
232
233
		/**
234
		 * Reset the parameters
235
		 */
236
		$this->parameters = array();
237
	}
238
239
240
	public function bindMore( $parray )
241
	{
242
		if ( !count( $this->parameters ) && is_array( $parray ) ) {
243
			$columns = array_keys( $parray );
244
			foreach ( $columns as $i => &$column ) {
245
				$this->bind( $column, $parray[ $column ] );
246
			}
247
		}
248
	}
249
250
	public function bind( $para, $value )
251
	{
252
		$this->parameters[ sizeof( $this->parameters ) ] = [ ":" . $para, $value ];
253
	}
254
255
256
	public function CloseConnection()
257
	{
258
		$this->pdo = null;
259
	}
260
261
262
	/**
263
	 * @param $queryString
264
	 * @return string
265
	 */
266
	public static function getQueryStatement( $queryString )
267
	{
268
		$queryString = trim( $queryString );
269
270
		if ( $queryString === '' ) {
271
			return self::QUERY_TYPE_EMPTY;
272
		}
273
274
		if ( preg_match( '/^(select|insert|update|delete|replace|show|desc|explain)[\s]+/i', $queryString, $matches ) ) {
275
			switch ( strtolower( $matches[ 1 ] ) ) {
276
				case 'select':
277
					return self::QUERY_TYPE_SELECT;
278
				case 'insert':
279
					return self::QUERY_TYPE_INSERT;
280
				case 'update':
281
					return self::QUERY_TYPE_UPDATE;
282
				case 'delete':
283
					return self::QUERY_TYPE_DELETE;
284
				case 'replace':
285
					return self::QUERY_TYPE_REPLACE;
286
				case 'explain':
287
					return self::QUERY_TYPE_EXPLAIN;
288
				default:
289
					return self::QUERY_TYPE_OTHER;
290
			}
291
		}
292
		else {
293
			return self::QUERY_TYPE_OTHER;
294
		}
295
	}
296
297
	/**
298
	 * @param array $arr
299
	 * @return bool
300
	 */
301
	public static function isArrayAssoc( array $arr )
302
	{
303
		if ( array() === $arr )
304
			return false;
305
306
		return array_keys( $arr ) !== range( 0, count( $arr ) - 1 );
307
	}
308
309
310
	/**
311
	 * @return DbService
312
	 */
313
	public static function getInstance()
314
	{
315
		if ( null === self::$instance ) {
316
			self::$instance = new self();
317
		}
318
319
		return self::$instance;
320
	}
321
322
}