Passed
Push — master ( 0a6ac4...650973 )
by Adrian
01:37
created

DbService::createPdoConnection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
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_OTHER = 'OTHER';
22
	const QUERY_TYPE_EXPLAIN = 'EXPLAIN';
23
24
	const ON_ERROR_THROW_EXCEPTION = 1;
25
	const ON_ERROR_RETURN_ERROR = 2;
26
27
	const QUERY_RESULT_TYPE_ARRAY = 'array';
28
	const QUERY_RESULT_TYPE_NUMBER = 'number';
29
	const QUERY_RESULT_TYPE_NULL = 'null';
30
31
	/**
32
	 * @var DbService
33
	 */
34
	private static $instance;
35
36
	/**
37
	 * @var \PDO
38
	 */
39
	private $pdo;
40
41
	/**
42
	 * @var \PDOStatement
43
	 */
44
	private $sQuery;
45
46
	/**
47
	 * @var array
48
	 */
49
	private $parameters = [];
50
51
	/**
52
	 * @var string;
53
	 */
54
	private $lastStatement;
55
56
	/**
57
	 * @var bool
58
	 */
59
	private $forceToMaster = false;
60
61
62
	/**
63
	 * @return $this
64
	 */
65
	public function withMasterOnly()
66
	{
67
		$this->forceToMaster = true;
68
69
		return $this;
70
	}
71
72
	/**
73
	 * @return $this
74
	 */
75
	public function withOutMasterOnly()
76
	{
77
		$this->forceToMaster = false;
78
79
		return $this;
80
	}
81
82
	/**
83
	 * @param string $query
84
	 * @param array $params
85
	 * @param int $fetchMode
86
	 * @return array|int|null
87
	 */
88
	public function query( $query, $params = null, $fetchMode = \PDO::FETCH_ASSOC )
89
	{
90
91
		$this->queryInit( $query, $params );
92
		$resultType = $this->getResultType( $this->lastStatement );
93
94
		switch ( $resultType ) {
95
			case self::QUERY_RESULT_TYPE_ARRAY:
96
				$result = $this->sQuery->fetchAll( $fetchMode );
97
				break;
98
			case self::QUERY_RESULT_TYPE_NUMBER:
99
				$result = $this->sQuery->rowCount();
100
				break;
101
			default:
102
				$result = null;
103
				break;
104
		}
105
106
		$this->sQuery->closeCursor();
107
108
		return $result;
109
	}
110
111
	/**
112
	 * @param $query
113
	 * @param array $params
114
	 * @return array|null
115
	 */
116
	public function column( $query, $params = null )
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
		$Columns = $this->sQuery->fetchAll( \PDO::FETCH_NUM );
124
125
		$column = null;
126
127
		foreach ( $Columns as $cells ) {
128
			$column[] = $cells[ 0 ];
129
		}
130
131
		return $column;
132
	}
133
134
	/**
135
	 * @param string $query
136
	 * @param array $params
137
	 * @param int $fetchmode
138
	 * @return array|mixed
139
	 */
140 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...
141
	{
142
		$this->queryInit( $query, $params );
143
144
		if ( $this->lastStatement === self::QUERY_TYPE_EXPLAIN )
145
			return $this->sQuery->fetchAll( \PDO::FETCH_ASSOC );
146
147
		$result = $this->sQuery->fetch( $fetchmode );
148
		$this->sQuery->closeCursor(); // Frees up the connection to the server so that other SQL statements may be issued,
149
150
		return $result;
151
	}
152
153
	/**
154
	 * @param string $query
155
	 * @param array $params
156
	 * @return mixed|array
157
	 */
158 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...
159
	{
160
		$this->queryInit( $query, $params );
161
162
		if ( $this->lastStatement === self::QUERY_TYPE_EXPLAIN )
163
			return $this->sQuery->fetchAll( \PDO::FETCH_ASSOC );
164
165
		$result = $this->sQuery->fetchColumn();
166
		$this->sQuery->closeCursor(); // Frees up the connection to the server so that other SQL statements may be issued
167
168
		return $result;
169
	}
170
171
172
	/**
173
	 * @param string $statement
174
	 * @return string
175
	 */
176
	private function getResultType( $statement )
177
	{
178
		switch ( $statement ) {
179
180
			case self::QUERY_TYPE_SELECT:
181
			case self::QUERY_TYPE_SHOW:
182
			case self::QUERY_TYPE_DESC:
183
			case self::QUERY_TYPE_EXPLAIN:
184
				return self::QUERY_RESULT_TYPE_ARRAY;
185
186
			case self::QUERY_TYPE_INSERT:
187
			case self::QUERY_TYPE_UPDATE:
188
			case self::QUERY_TYPE_DELETE:
189
				return self::QUERY_RESULT_TYPE_NUMBER;
190
191
			default:
192
				return self::QUERY_RESULT_TYPE_NULL;
193
194
		}
195
	}
196
197
	/**
198
	 * Create necessary type connection
199
	 */
200
	private function createPdoConnection()
201
	{
202
		$this->pdo = $this->forceToMaster
203
			? DbConnect::getInstance()->getMasterConnection()
204
			: DbConnect::getInstance()->getConnection( $this->lastStatement );
205
	}
206
207
	/**
208
	 * @param string $query
209
	 * @param array $parameters
210
	 * @throws DbException
211
	 */
212
	private function queryInit( $query, $parameters = [] )
213
	{
214
		$this->lastStatement = self::getQueryStatement( $query );
215
		$this->createPdoConnection();
216
		$startQueryTime = microtime( true );
217
218
		try {
219
220
			/**
221
			 * Prepare query
222
			 */
223
			$this->sQuery = $this->pdo->prepare( $query );
224
225
			/**
226
			 * Add parameters to the parameter array
227
			 */
228
			if ( self::isArrayAssoc( $parameters ) )
229
				$this->bindMore( $parameters );
230
			else
231
				foreach ( $parameters as $key => $val )
232
					$this->parameters[] = array( $key + 1, $val );
233
234
			if ( count( $this->parameters ) ) {
235
				foreach ( $this->parameters as $param => $value ) {
236
					if ( is_int( $value[ 1 ] ) ) {
237
						$type = \PDO::PARAM_INT;
238
					}
239
					elseif ( is_bool( $value[ 1 ] ) ) {
240
						$type = \PDO::PARAM_BOOL;
241
					}
242
					elseif ( is_null( $value[ 1 ] ) ) {
243
						$type = \PDO::PARAM_NULL;
244
					}
245
					else {
246
						$type = \PDO::PARAM_STR;
247
					}
248
					$this->sQuery->bindValue( $value[ 0 ], $value[ 1 ], $type );
249
				}
250
			}
251
252
			$this->sQuery->execute();
253
254
			if ( DbConfig::getInstance()->isEnableLogQueryDuration() ) {
255
				$duration = microtime( true ) - $startQueryTime;
256
				DbLog::getInstance()->writeQueryDuration( $query, $duration );
257
			}
258
259
		} catch ( \PDOException $e ) {
260
			if ( DbConfig::getInstance()->isEnableLogErrors() ) {
261
				DbLog::getInstance()->writeQueryErrors( $query, $e );
262
			}
263
			throw new DbException( 'Database query runtime error!', DbException::DB_QUERY_ERROR );
264
		}
265
266
		/**
267
		 * Reset the parameters
268
		 */
269
		$this->parameters = array();
270
	}
271
272
273
	public function bindMore( $parray )
274
	{
275
		if ( !count( $this->parameters ) && is_array( $parray ) ) {
276
			$columns = array_keys( $parray );
277
			foreach ( $columns as $i => &$column ) {
278
				$this->bind( $column, $parray[ $column ] );
279
			}
280
		}
281
	}
282
283
	public function bind( $para, $value )
284
	{
285
		$this->parameters[ sizeof( $this->parameters ) ] = [ ":" . $para, $value ];
286
	}
287
288
289
	public function CloseConnection()
290
	{
291
		$this->pdo = null;
292
	}
293
294
295
	/**
296
	 * @param $queryString
297
	 * @return string
298
	 */
299
	public static function getQueryStatement( $queryString )
300
	{
301
		$queryString = trim( $queryString );
302
303
		if ( preg_match( '/^(select|insert|update|delete|replace|show|desc|explain)[\s]+/i', $queryString, $matches ) )
304
			return strtoupper( $matches[ 1 ] );
305
		else
306
			return self::QUERY_TYPE_OTHER;
307
	}
308
309
	/**
310
	 * @param array $arr
311
	 * @return bool
312
	 */
313
	public static function isArrayAssoc( array $arr )
314
	{
315
		if ( array() === $arr )
316
			return false;
317
318
		return array_keys( $arr ) !== range( 0, count( $arr ) - 1 );
319
	}
320
321
322
	/**
323
	 * @return DbService
324
	 */
325
	public static function getInstance()
326
	{
327
		if ( null === self::$instance ) {
328
			self::$instance = new self();
329
		}
330
331
		return self::$instance;
332
	}
333
334
}