Completed
Pull Request — master (#245)
by Tomáš
02:43
created

Connection   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 410
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 12
Bugs 5 Features 0
Metric Value
wmc 42
c 12
b 5
f 0
lcom 2
cbo 9
dl 0
loc 410
rs 8.295

21 Methods

Rating   Name   Duplication   Size   Complexity  
A bindEntityManager() 0 5 1
A quoteIdentifier() 0 9 2
A delete() 0 9 2
A update() 0 14 3
A insert() 0 9 2
A prepare() 0 15 2
A createQueryBuilder() 0 8 2
A setSchemaTypes() 0 4 1
A setDbalTypes() 0 4 1
B connect() 0 29 6
A getDatabasePlatform() 0 8 2
B ping() 0 26 4
A create() 0 8 2
A getReflection() 0 4 1
A __call() 0 4 1
A __callStatic() 0 4 1
A extensionMethod() 0 13 3
A __get() 0 4 1
A __set() 0 9 2
A __isset() 0 4 1
A __unset() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like Connection 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 Connection, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the Kdyby (http://www.kdyby.org)
5
 *
6
 * Copyright (c) 2008 Filip Procházka ([email protected])
7
 *
8
 * For the full copyright and license information, please view the file license.txt that was distributed with this source code.
9
 */
10
11
namespace Kdyby\Doctrine;
12
13
use Doctrine;
14
use Doctrine\Common\EventManager;
15
use Doctrine\DBAL\DBALException;
16
use Doctrine\DBAL\Driver;
17
use Doctrine\DBAL\Statement;
18
use Kdyby;
19
use Nette;
20
use Nette\Utils\ObjectMixin;
21
use PDO;
22
use Tracy;
23
24
25
26
/**
27
 * @author Filip Procházka <[email protected]>
28
 */
29
class Connection extends Doctrine\DBAL\Connection
30
{
31
	/**
32
	 * @var bool
33
	 */
34
	public $throwOldKdybyExceptions = FALSE;
35
36
	/** @deprecated */
37
	const MYSQL_ERR_UNIQUE = 1062;
38
	/** @deprecated */
39
	const MYSQL_ERR_NOT_NULL = 1048;
40
41
	/** @deprecated */
42
	const SQLITE_ERR_UNIQUE = 19;
43
44
	/** @deprecated */
45
	const POSTGRE_ERR_UNIQUE = 23505; // todo: verify, source: http://www.postgresql.org/docs/8.2/static/errcodes-appendix.html
46
47
	/**
48
	 * @var Doctrine\ORM\EntityManager
49
	 */
50
	private $entityManager;
51
52
	/**
53
	 * @var array
54
	 */
55
	private $schemaTypes = [];
56
57
	/**
58
	 * @var array
59
	 */
60
	private $dbalTypes = [];
61
62
63
64
	/**
65
	 * @internal
66
	 * @param Doctrine\ORM\EntityManager $em
67
	 * @return $this
68
	 */
69
	public function bindEntityManager(Doctrine\ORM\EntityManager $em)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
70
	{
71
		$this->entityManager = $em;
72
		return $this;
73
	}
74
75
76
77
	/**
78
	 * Tries to autodetect, if identifier has to be quoted and quotes it.
79
	 *
80
	 * @param string $expression
81
	 * @return string
82
	 */
83
	public function quoteIdentifier($expression)
84
	{
85
		$expression = trim($expression);
86
		if ($expression[0] === $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
87
			return $expression; // already quoted
88
		}
89
90
		return parent::quoteIdentifier($expression);
91
	}
92
93
94
95
	/**
96
	 * {@inheritdoc}
97
	 */
98
	public function delete($tableExpression, array $identifier, array $types = [])
99
	{
100
		$fixedIdentifier = [];
101
		foreach ($identifier as $columnName => $value) {
102
			$fixedIdentifier[$this->quoteIdentifier($columnName)] = $value;
103
		}
104
105
		return parent::delete($this->quoteIdentifier($tableExpression), $fixedIdentifier, $types);
106
	}
107
108
109
110
	/**
111
	 * {@inheritdoc}
112
	 */
113
	public function update($tableExpression, array $data, array $identifier, array $types = [])
114
	{
115
		$fixedData = [];
116
		foreach ($data as $columnName => $value) {
117
			$fixedData[$this->quoteIdentifier($columnName)] = $value;
118
		}
119
120
		$fixedIdentifier = [];
121
		foreach ($identifier as $columnName => $value) {
122
			$fixedIdentifier[$this->quoteIdentifier($columnName)] = $value;
123
		}
124
125
		return parent::update($this->quoteIdentifier($tableExpression), $fixedData, $fixedIdentifier, $types);
126
	}
127
128
129
130
	/**
131
	 * {@inheritdoc}
132
	 */
133
	public function insert($tableExpression, array $data, array $types = [])
134
	{
135
		$fixedData = [];
136
		foreach ($data as $columnName => $value) {
137
			$fixedData[$this->quoteIdentifier($columnName)] = $value;
138
		}
139
140
		return parent::insert($this->quoteIdentifier($tableExpression), $fixedData, $types);
141
	}
142
143
144
145
	/**
146
	 * Prepares an SQL statement.
147
	 *
148
	 * @param string $statement The SQL statement to prepare.
149
	 * @throws DBALException
150
	 * @return Statement The prepared statement.
151
	 */
152
	public function prepare($statement)
153
	{
154
		$this->connect();
155
156
		try {
157
			$stmt = new Statement($statement, $this);
158
159
		} catch (\Exception $ex) {
160
			throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement);
161
		}
162
163
		$stmt->setFetchMode(PDO::FETCH_ASSOC);
164
165
		return $stmt;
166
	}
167
168
169
170
	/**
171
	 * @return Doctrine\DBAL\Query\QueryBuilder|NativeQueryBuilder
172
	 */
173
	public function createQueryBuilder()
174
	{
175
		if (!$this->entityManager) {
176
			return parent::createQueryBuilder();
177
		}
178
179
		return new NativeQueryBuilder($this->entityManager);
180
	}
181
182
183
184
	/**
185
	 * @param array $schemaTypes
186
	 */
187
	public function setSchemaTypes(array $schemaTypes)
188
	{
189
		$this->schemaTypes = $schemaTypes;
190
	}
191
192
193
194
	/**
195
	 * @param array $dbalTypes
196
	 */
197
	public function setDbalTypes(array $dbalTypes)
198
	{
199
		$this->dbalTypes = $dbalTypes;
200
	}
201
202
203
204
	public function connect()
205
	{
206
		if ($this->isConnected()) {
207
			return FALSE;
208
		}
209
210
		foreach ($this->dbalTypes as $name => $className) {
211
			if (DbalType::hasType($name)) {
212
				DbalType::overrideType($name, $className);
213
214
			} else {
215
				DbalType::addType($name, $className);
216
			}
217
		}
218
219
		parent::connect();
220
221
		$platform = $this->getDatabasePlatform();
222
223
		foreach ($this->schemaTypes as $dbType => $doctrineType) {
224
			$platform->registerDoctrineTypeMapping($dbType, $doctrineType);
225
		}
226
227
		foreach ($this->dbalTypes as $type => $className) {
228
			$platform->markDoctrineTypeCommented(DbalType::getType($type));
229
		}
230
231
		return TRUE;
232
	}
233
234
235
236
	/**
237
	 * @return Doctrine\DBAL\Platforms\AbstractPlatform
238
	 */
239
	public function getDatabasePlatform()
240
	{
241
		if (!$this->isConnected()) {
242
			$this->connect();
243
		}
244
245
		return parent::getDatabasePlatform();
246
	}
247
248
249
250
	public function ping()
251
	{
252
		$conn = $this->getWrappedConnection();
253
		if ($conn instanceof Driver\PingableConnection) {
254
			return $conn->ping();
255
		}
256
257
		set_error_handler(function ($severity, $message) {
258
			throw new \PDOException($message, $severity);
259
		});
260
261
		try {
262
			$this->query($this->getDatabasePlatform()->getDummySelectSQL());
263
			restore_error_handler();
264
265
			return TRUE;
266
267
		} catch (DBALException $e) {
268
			restore_error_handler();
269
			return FALSE;
270
271
		} catch (\Exception $e) {
272
			restore_error_handler();
273
			throw $e;
274
		}
275
	}
276
277
278
279
	/**
280
	 * @param array $params
281
	 * @param \Doctrine\DBAL\Configuration $config
282
	 * @param \Doctrine\Common\EventManager $eventManager
283
	 * @param array $dbalTypes
0 ignored issues
show
Bug introduced by
There is no parameter named $dbalTypes. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
284
	 * @param array $schemaTypes
0 ignored issues
show
Bug introduced by
There is no parameter named $schemaTypes. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
285
	 * @return Connection
286
	 */
287
	public static function create(array $params, Doctrine\DBAL\Configuration $config, EventManager $eventManager)
288
	{
289
		if (!isset($params['wrapperClass'])) {
290
			$params['wrapperClass'] = get_called_class();
291
		}
292
293
		return Doctrine\DBAL\DriverManager::getConnection($params, $config, $eventManager);
294
	}
295
296
297
298
	/*************************** Nette\Object ***************************/
299
300
301
302
	/**
303
	 * Access to reflection.
304
	 * @return \Nette\Reflection\ClassType
305
	 */
306
	public static function getReflection()
307
	{
308
		return new Nette\Reflection\ClassType(get_called_class());
309
	}
310
311
312
313
	/**
314
	 * Call to undefined method.
315
	 *
316
	 * @param string $name
317
	 * @param array $args
318
	 *
319
	 * @throws \Nette\MemberAccessException
320
	 * @return mixed
321
	 */
322
	public function __call($name, $args)
323
	{
324
		return ObjectMixin::call($this, $name, $args);
325
	}
326
327
328
329
	/**
330
	 * Call to undefined static method.
331
	 *
332
	 * @param string $name
333
	 * @param array $args
334
	 *
335
	 * @throws \Nette\MemberAccessException
336
	 * @return mixed
337
	 */
338
	public static function __callStatic($name, $args)
339
	{
340
		return ObjectMixin::callStatic(get_called_class(), $name, $args);
341
	}
342
343
344
345
	/**
346
	 * Adding method to class.
347
	 *
348
	 * @param $name
349
	 * @param null $callback
350
	 *
351
	 * @throws \Nette\MemberAccessException
352
	 * @return callable|null
353
	 */
354
	public static function extensionMethod($name, $callback = NULL)
355
	{
356
		if (strpos($name, '::') === FALSE) {
357
			$class = get_called_class();
358
		} else {
359
			list($class, $name) = explode('::', $name);
360
		}
361
		if ($callback === NULL) {
362
			return ObjectMixin::getExtensionMethod($class, $name);
363
		} else {
364
			ObjectMixin::setExtensionMethod($class, $name, $callback);
365
		}
366
	}
367
368
369
370
	/**
371
	 * Returns property value. Do not call directly.
372
	 *
373
	 * @param string $name
374
	 *
375
	 * @throws \Nette\MemberAccessException
376
	 * @return mixed
377
	 */
378
	public function &__get($name)
379
	{
380
		return ObjectMixin::get($this, $name);
381
	}
382
383
384
385
	/**
386
	 * Sets value of a property. Do not call directly.
387
	 *
388
	 * @param string $name
389
	 * @param mixed $value
390
	 *
391
	 * @throws \Nette\MemberAccessException
392
	 * @return void
393
	 */
394
	public function __set($name, $value)
395
	{
396
		if ($name === '_conn') {
397
			$this->_conn = $value;
398
			return;
399
		}
400
401
		ObjectMixin::set($this, $name, $value);
402
	}
403
404
405
406
	/**
407
	 * Is property defined?
408
	 *
409
	 * @param string $name
410
	 *
411
	 * @return bool
412
	 */
413
	public function __isset($name)
414
	{
415
		return ObjectMixin::has($this, $name);
416
	}
417
418
419
420
	/**
421
	 * Access to undeclared property.
422
	 *
423
	 * @param string $name
424
	 *
425
	 * @throws \Nette\MemberAccessException
426
	 * @return void
427
	 */
428
	public function __unset($name)
429
	{
430
		if ($name === '_conn') {
431
			$this->$name = NULL;
432
			return;
433
		}
434
435
		ObjectMixin::remove($this, $name);
436
	}
437
438
}
439