Completed
Push — master ( e72bde...c9688b )
by Filip
02:19
created

Panel::startQuery()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 26
rs 4.8196
cc 10
eloc 15
nc 7
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Diagnostics;
12
13
use Doctrine;
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Doctrine\Common\Persistence\Proxy;
16
use Doctrine\Common\Annotations\AnnotationException;
17
use Doctrine\DBAL\Platforms\AbstractPlatform;
18
use Doctrine\DBAL\Types\Type;
19
use Kdyby;
20
use Nette;
21
use Nette\Utils\Strings;
22
use Tracy\Bar;
23
use Tracy\BlueScreen;
24
use Tracy\Debugger;
25
use Tracy\Dumper;
26
use Tracy\Helpers;
27
use Tracy\IBarPanel;
28
29
30
31
/**
32
 * Debug panel for Doctrine
33
 *
34
 * @author David Grudl
35
 * @author Patrik Votoček
36
 * @author Filip Procházka <[email protected]>
37
 */
38
class Panel extends Nette\Object implements IBarPanel, Doctrine\DBAL\Logging\SQLLogger
39
{
40
41
	/**
42
	 * @var int logged time
43
	 */
44
	public $totalTime = 0;
45
46
	/**
47
	 * @var array
48
	 */
49
	public $queries = [];
50
51
	/**
52
	 * @var array
53
	 */
54
	public $failed = [];
55
56
	/**
57
	 * @var array
58
	 */
59
	public $skipPaths = [
60
		'vendor/nette/', 'src/Nette/',
61
		'vendor/doctrine/collections/', 'lib/Doctrine/Collections/',
62
		'vendor/doctrine/common/', 'lib/Doctrine/Common/',
63
		'vendor/doctrine/dbal/', 'lib/Doctrine/DBAL/',
64
		'vendor/doctrine/orm/', 'lib/Doctrine/ORM/',
65
		'vendor/kdyby/doctrine/', 'src/Kdyby/Doctrine/',
66
		'vendor/phpunit',
67
	];
68
69
	/**
70
	 * @var \Doctrine\DBAL\Connection
71
	 */
72
	private $connection;
73
74
	/**
75
	 * @var \Doctrine\ORM\EntityManager
76
	 */
77
	private $em;
78
79
80
81
	/***************** Doctrine\DBAL\Logging\SQLLogger ********************/
82
83
84
85
	/**
86
	 * @param string
87
	 * @param array
88
	 * @param array
89
	 */
90
	public function startQuery($sql, array $params = NULL, array $types = NULL)
91
	{
92
		Debugger::timer('doctrine');
93
94
		$source = NULL;
95
		foreach (debug_backtrace(FALSE) as $row) {
96
			if (isset($row['file']) && $this->filterTracePaths(realpath($row['file']))) {
97
				if (isset($row['class']) && stripos($row['class'], '\\' . Proxy::MARKER) !== FALSE) {
98
					if (!in_array('Doctrine\Common\Persistence\Proxy', class_implements($row['class']))) {
99
						continue;
100
101
					} elseif (isset($row['function']) && $row['function'] === '__load') {
102
						continue;
103
					}
104
105
				} elseif (stripos($row['file'], DIRECTORY_SEPARATOR . Proxy::MARKER) !== FALSE) {
106
					continue;
107
				}
108
109
				$source = [$row['file'], (int) $row['line']];
110
				break;
111
			}
112
		}
113
114
		$this->queries[] = [$sql, $params, NULL, $types, $source];
115
	}
116
117
118
119
	/**
120
	 * @param string $file
121
	 * @return boolean
122
	 */
123
	protected function filterTracePaths($file)
124
	{
125
		$file = str_replace(DIRECTORY_SEPARATOR, '/', $file);
126
		$return = is_file($file);
127
		foreach ($this->skipPaths as $path) {
128
			if (!$return) {
129
				break;
130
			}
131
			$return = $return && strpos($file, '/' . trim($path, '/') . '/') === FALSE;
132
		}
133
		return $return;
134
	}
135
136
137
138
	/**
139
	 * @return array
140
	 */
141
	public function stopQuery()
142
	{
143
		$keys = array_keys($this->queries);
144
		$key = end($keys);
145
		$this->queries[$key][2] = $time = Debugger::timer('doctrine');
146
		$this->totalTime += $time;
147
148
		return $this->queries[$key] + array_fill_keys(range(0, 4), NULL);
149
	}
150
151
152
153
	/**
154
	 * @param \Exception|\Throwable $exception
155
	 */
156
	public function queryFailed($exception)
157
	{
158
		$this->failed[spl_object_hash($exception)] = $this->stopQuery();
159
	}
160
161
162
163
	/***************** Tracy\IBarPanel ********************/
164
165
166
167
	/**
168
	 * @return string
169
	 */
170
	public function getTab()
171
	{
172
		return '<span title="Doctrine 2">'
173
			. '<svg viewBox="0 0 2048 2048"><path fill="#aaa" d="M1024 896q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0 768q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0-384q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0-1152q208 0 385 34.5t280 93.5 103 128v128q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-128q0-69 103-128t280-93.5 385-34.5z"></path></svg>'
174
			. '<span class="tracy-label">'
175
			. count($this->queries) . ' queries'
176
			. ($this->totalTime ? ' / ' . sprintf('%0.1f', $this->totalTime * 1000) . ' ms' : '')
177
			. '</span>'
178
			. '</span>';
179
	}
180
181
182
183
	/**
184
	 * @return string
185
	 */
186
	public function getPanel()
187
	{
188
		if (empty($this->queries)) {
189
			return '';
190
		}
191
192
		$connParams = $this->connection->getParams();
193
		if ($connParams['driver'] === 'pdo_sqlite' && isset($connParams['path'])) {
194
			$host = 'path: ' . basename($connParams['path']);
195
196
		} else {
197
			$host = sprintf('host: %s%s/%s',
198
				$this->connection->getHost(),
199
				(($p = $this->connection->getPort()) ? ':' . $p : ''),
200
				$this->connection->getDatabase()
201
			);
202
		}
203
204
		return
205
			$this->renderStyles() .
206
			sprintf('<h1>Queries: %s %s, %s</h1>',
207
				count($this->queries),
208
				($this->totalTime ? ', time: ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms' : ''),
209
				$host
210
			) .
211
			'<div class="nette-inner tracy-inner nette-Doctrine2Panel">' .
212
				implode('<br>', array_filter([
213
					$this->renderPanelCacheStatistics(),
214
					$this->renderPanelQueries()
215
				])) .
216
			'</div>';
217
	}
218
219
220
221
	private function renderPanelCacheStatistics()
222
	{
223
		if (empty($this->em)) {
224
			return '';
225
		}
226
227
		$config = $this->em->getConfiguration();
228
		if (!$config->isSecondLevelCacheEnabled()) {
229
			return '';
230
		}
231
232
		$loggerChain = $config->getSecondLevelCacheConfiguration()
233
			->getCacheLogger();
234
235
		if (!$loggerChain instanceof Doctrine\ORM\Cache\Logging\CacheLoggerChain) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Cache\Logging\CacheLoggerChain does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
236
			return '';
237
		}
238
239
		if (!$statistics = $loggerChain->getLogger('statistics')) {
240
			return '';
241
		}
242
243
		return Dumper::toHtml($statistics, [Dumper::DEPTH => 5]);
244
	}
245
246
247
248
	private function renderPanelQueries()
249
	{
250
		if (empty($this->queries)) {
251
			return "";
252
		}
253
254
		$s = "";
255
		foreach ($this->queries as $query) {
256
			$s .= $this->processQuery($query);
257
		}
258
259
		return '<table><tr><th>ms</th><th>SQL Statement</th></tr>' . $s . '</table>';
260
	}
261
262
263
264
	/**
265
	 * @return string
266
	 */
267
	protected function renderStyles()
268
	{
269
		return '<style>
270
			#nette-debug td.nette-Doctrine2Panel-sql { background: white !important}
271
			#nette-debug .nette-Doctrine2Panel-source { color: #BBB !important }
272
			#nette-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto }
273
			#tracy-debug td.nette-Doctrine2Panel-sql { background: white !important}
274
			#tracy-debug .nette-Doctrine2Panel-source { color: #BBB !important }
275
			#tracy-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto }
276
		</style>';
277
	}
278
279
280
281
	/**
282
	 * @param array
283
	 * @return string
284
	 */
285
	protected function processQuery(array $query)
286
	{
287
		$h = 'htmlspecialchars';
288
		list($sql, $params, $time, $types, $source) = $query;
289
290
		$s = self::highlightQuery(static::formatQuery($sql, (array) $params, (array) $types, $this->connection ? $this->connection->getDatabasePlatform() : NULL));
291
		if ($source) {
292
			$s .= self::editorLink($source[0], $source[1], $h('.../' . basename(dirname($source[0]))) . '/<b>' . $h(basename($source[0])) . '</b>');
293
		}
294
295
		return '<tr><td>' . sprintf('%0.3f', $time * 1000) . '</td>' .
296
			'<td class = "nette-Doctrine2Panel-sql">' . $s . '</td></tr>';
297
	}
298
299
300
301
	/****************** Exceptions handling *********************/
302
303
304
305
	/**
306
	 * @param \Exception|\Throwable $e
307
	 * @return void|array
308
	 */
309
	public function renderQueryException($e)
310
	{
311
		if ($e instanceof \PDOException && count($this->queries)) {
312
			$types = $params = [];
313
314
			if ($this->connection !== NULL) {
315
				if (!$e instanceof Kdyby\Doctrine\DBALException || $e->connection !== $this->connection) {
316
					return NULL;
317
318
				} elseif (!isset($this->failed[spl_object_hash($e)])) {
319
					return NULL;
320
				}
321
322
				list($sql, $params, , , $source) = $this->failed[spl_object_hash($e)];
323
324
			} else {
325
				list($sql, $params, , $types, $source) = end($this->queries) + range(1, 5);
326
			}
327
328
			if (!$sql) {
329
				return NULL;
330
			}
331
332
			return [
333
				'tab' => 'SQL',
334
				'panel' => $this->dumpQuery($sql, $params, $types, $source),
335
			];
336
337
		} elseif ($e instanceof Kdyby\Doctrine\QueryException && $e->query !== NULL) {
338
			if ($e->query instanceof Doctrine\ORM\Query) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Query does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
339
				return [
340
					'tab' => 'DQL',
341
					'panel' => $this->dumpQuery($e->query->getDQL(), $e->query->getParameters()),
342
				];
343
344
			} elseif ($e->query instanceof Kdyby\Doctrine\NativeQueryWrapper) {
345
				return [
346
					'tab' => 'Native SQL',
347
					'panel' => $this->dumpQuery($e->query->getSQL(), $e->query->getParameters()),
348
				];
349
			}
350
		}
351
	}
352
353
354
355
	/**
356
	 * @param \Exception|\Throwable $e
357
	 * @param \Nette\DI\Container $dic
358
	 * @return array
359
	 */
360
	public static function renderException($e, Nette\DI\Container $dic)
361
	{
362
		if ($e instanceof AnnotationException) {
0 ignored issues
show
Bug introduced by
The class Doctrine\Common\Annotations\AnnotationException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
363
			if ($dump = self::highlightAnnotationLine($e)) {
364
				return [
365
					'tab' => 'Annotation',
366
					'panel' => $dump,
367
				];
368
			}
369
370
		} elseif ($e instanceof Doctrine\ORM\Mapping\MappingException) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Mapping\MappingException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
371
			if ($invalidEntity = Strings::match($e->getMessage(), '~^Class "([\\S]+)" .*? is not .*? valid~i')) {
372
				$refl = Nette\Reflection\ClassType::from($invalidEntity[1]);
373
				$file = $refl->getFileName();
374
				$errorLine = $refl->getStartLine();
375
376
				return [
377
					'tab' => 'Invalid entity',
378
					'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' .
379
						BlueScreen::highlightFile($file, $errorLine),
380
				];
381
			}
382
383
		} elseif ($e instanceof Doctrine\DBAL\Schema\SchemaException && $dic && ($em = $dic->getByType('Kdyby\Doctrine\EntityManager', FALSE))) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Schema\SchemaException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
384
			/** @var Kdyby\Doctrine\EntityManager $em */
385
386
			if ($invalidTable = Strings::match($e->getMessage(), '~table \'(.*?)\'~i')) {
387
				foreach ($em->getMetadataFactory()->getAllMetadata() as $class) {
388
					/** @var Kdyby\Doctrine\Mapping\ClassMetadata $class */
389
					if ($class->getTableName() === $invalidTable[1]) {
390
						$refl = $class->getReflectionClass();
391
						break;
392
					}
393
				}
394
395
				if (!isset($refl)) {
396
					return NULL;
397
				}
398
399
				$file = $refl->getFileName();
400
				$errorLine = $refl->getStartLine();
401
402
				return [
403
					'tab' => 'Invalid schema',
404
					'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' .
405
						BlueScreen::highlightFile($file, $errorLine),
406
				];
407
			}
408
409
		} elseif ($e instanceof Kdyby\Doctrine\DBALException && $e->query) {
410
			return [
411
				'tab' => 'SQL',
412
				'panel' => self::highlightQuery(static::formatQuery($e->query, $e->params, [])),
413
			];
414
415
		} elseif ($e instanceof Doctrine\DBAL\Exception\DriverException) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Exception\DriverException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
416
			if (($prev = $e->getPrevious()) && ($item = Helpers::findTrace($e->getTrace(), 'Doctrine\DBAL\DBALException::driverExceptionDuringQuery'))) {
417
				/** @var \Doctrine\DBAL\Driver $driver */
418
				$driver = $item['args'][0];
419
				$params = isset($item['args'][3]) ? $item['args'][3] : [];
420
421
				return [
422
					'tab' => 'SQL',
423
					'panel' => self::highlightQuery(static::formatQuery($item['args'][2], $params, [], $driver->getDatabasePlatform())),
424
				];
425
			}
426
427
		} elseif ($e instanceof Doctrine\ORM\Query\QueryException) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Query\QueryException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
428
			if (($prev = $e->getPrevious()) && preg_match('~^(SELECT|INSERT|UPDATE|DELETE)\s+.*~i', $prev->getMessage())) {
429
				return [
430
					'tab' => 'DQL',
431
					'panel' => self::highlightQuery(static::formatQuery($prev->getMessage(), [], [])),
432
				];
433
			}
434
435
		} elseif ($e instanceof \PDOException) {
436
			$params = [];
437
438
			if (isset($e->queryString)) {
439
				$sql = $e->queryString;
0 ignored issues
show
Bug introduced by
The property queryString does not seem to exist. Did you mean string?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
440
441
			} elseif ($item = Helpers::findTrace($e->getTrace(), 'Doctrine\DBAL\Connection::executeQuery')) {
442
				$sql = $item['args'][0];
443
				$params = $item['args'][1];
444
445
			} elseif ($item = Helpers::findTrace($e->getTrace(), 'PDO::query')) {
446
				$sql = $item['args'][0];
447
448
			} elseif ($item = Helpers::findTrace($e->getTrace(), 'PDO::prepare')) {
449
				$sql = $item['args'][0];
450
			}
451
452
			return isset($sql) ? [
453
				'tab' => 'SQL',
454
				'panel' => self::highlightQuery(static::formatQuery($sql, $params, [])),
455
			] : NULL;
456
		}
457
458
		return NULL;
459
	}
460
461
462
463
	/**
464
	 * @param string $query
465
	 * @param array|Doctrine\Common\Collections\ArrayCollection $params
466
	 * @param array $types
467
	 * @param string $source
468
	 *
469
	 * @return array
470
	 */
471
	protected function dumpQuery($query, $params, array $types = [], $source = NULL)
472
	{
473
		if ($params instanceof ArrayCollection) {
0 ignored issues
show
Bug introduced by
The class Doctrine\Common\Collections\ArrayCollection does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
474
			$tmp = [];
475
			$tmpTypes = [];
476
			foreach ($params as $key => $param) {
477
				if ($param instanceof Doctrine\ORM\Query\Parameter) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ORM\Query\Parameter does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
478
					$tmpTypes[$param->getName()] = $param->getType();
479
					$tmp[$param->getName()] = $param->getValue();
480
					continue;
481
				}
482
				$tmp[$key] = $param;
483
			}
484
			$params = $tmp;
485
			$types = $tmpTypes;
486
		}
487
488
		// query
489
		$s = '<p><b>Query</b></p><table><tr><td class="nette-Doctrine2Panel-sql">';
490
		$s .= self::highlightQuery(static::formatQuery($query, $params, $types, $this->connection ? $this->connection->getDatabasePlatform() : NULL));
491
		$s .= '</td></tr></table>';
492
493
		$e = NULL;
494
		if ($source && is_array($source)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $source of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
495
			list($file, $line) = $source;
496
			$e = '<p><b>File:</b> ' . self::editorLink($file, $line) . '</p>';
497
		}
498
499
		// styles and dump
500
		return $this->renderStyles() . '<div class="nette-inner tracy-inner nette-Doctrine2Panel">' . $e . $s . '</div>';
501
	}
502
503
504
505
	/**
506
	 * Returns syntax highlighted SQL command.
507
	 * This method is same as Nette\Database\Helpers::dumpSql except for parameters handling.
508
	 * @link https://github.com/nette/database/blob/667143b2d5b940f78c8dc9212f95b1bbc033c6a3/src/Database/Helpers.php#L75-L138
509
	 * @author David Grudl
510
	 * @param string $sql
511
	 * @return string
512
	 */
513
	public static function highlightQuery($sql)
514
	{
515
		static $keywords1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
516
		static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE|WITH|INSTANCE\s+OF';
517
518
		// insert new lines
519
		$sql = " $sql ";
520
		$sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
521
522
		// reduce spaces
523
		$sql = preg_replace('#[ \t]{2,}#', ' ', $sql);
524
525
		$sql = wordwrap($sql, 100);
526
		$sql = preg_replace('#([ \t]*\r?\n){2,}#', "\n", $sql);
527
528
		// syntax highlight
529
		$sql = htmlspecialchars($sql, ENT_IGNORE, 'UTF-8');
530
		$sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function ($matches) {
531
			if (!empty($matches[1])) { // comment
532
				return '<em style="color:gray">' . $matches[1] . '</em>';
533
534
			} elseif (!empty($matches[2])) { // error
535
				return '<strong style="color:red">' . $matches[2] . '</strong>';
536
537
			} elseif (!empty($matches[3])) { // most important keywords
538
				return '<strong style="color:blue">' . $matches[3] . '</strong>';
539
540
			} elseif (!empty($matches[4])) { // other keywords
541
				return '<strong style="color:green">' . $matches[4] . '</strong>';
542
			}
543
		}, $sql);
544
545
		return '<pre class="dump">' . trim($sql) . "</pre>\n";
546
	}
547
548
549
550
	/**
551
	 * @param string $query
552
	 * @param array $params
553
	 * @param array $types
554
	 * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
555
	 * @throws \Doctrine\DBAL\DBALException
556
	 * @throws \Nette\Utils\RegexpException
557
	 * @return string
558
	 */
559
	public static function formatQuery($query, $params, array $types = [], AbstractPlatform $platform = NULL)
560
	{
561
		if (!$platform) {
562
			$platform = new Doctrine\DBAL\Platforms\MySqlPlatform();
563
		}
564
565
		if (!$types) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $types of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
566
			foreach ($params as $key => $param) {
567
				if (is_array($param)) {
568
					$types[$key] = Doctrine\DBAL\Connection::PARAM_STR_ARRAY;
569
570
				} else {
571
					$types[$key] = 'string';
572
				}
573
			}
574
		}
575
576
		try {
577
			list($query, $params, $types) = \Doctrine\DBAL\SQLParserUtils::expandListParameters($query, $params, $types);
578
		} catch (Doctrine\DBAL\SQLParserUtilsException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class Doctrine\DBAL\SQLParserUtilsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
579
		}
580
581
		$formattedParams = [];
582
		foreach ($params as $key => $param) {
583
			if (isset($types[$key])) {
584
				if (is_scalar($types[$key]) && array_key_exists($types[$key], Type::getTypesMap())) {
585
					$types[$key] = Type::getType($types[$key]);
586
				}
587
588
				/** @var Type[] $types */
589
				if ($types[$key] instanceof Type) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Types\Type does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
590
					$param = $types[$key]->convertToDatabaseValue($param, $platform);
591
				}
592
			}
593
594
			$formattedParams[] = SimpleParameterFormatter::format($param);
595
		}
596
		$params = $formattedParams;
597
598
		if (Nette\Utils\Validators::isList($params)) {
599
			$parts = explode('?', $query);
600
			if (count($params) > $parts) {
601
				throw new Kdyby\Doctrine\InvalidStateException("Too mny parameters passed to query.");
602
			}
603
604
			return implode('', Kdyby\Doctrine\Helpers::zipper($parts, $params));
605
		}
606
607
		return Strings::replace($query, '~(\\:[a-z][a-z0-9]*|\\?[0-9]*)~i', function ($m) use (&$params) {
608
			if (substr($m[0], 0, 1) === '?') {
609
				if (strlen($m[0]) > 1) {
610
					if (isset($params[$k = substr($m[0], 1)])) {
611
						return $params[$k];
612
					}
613
614
				} else {
615
					return array_shift($params);
616
				}
617
618
			} else {
619
				if (isset($params[$k = substr($m[0], 1)])) {
620
					return $params[$k];
621
				}
622
			}
623
624
			return $m[0];
625
		});
626
	}
627
628
629
630
	/**
631
	 * @param \Doctrine\Common\Annotations\AnnotationException $e
632
	 * @return string|bool
633
	 */
634
	public static function highlightAnnotationLine(AnnotationException $e)
635
	{
636
		foreach ($e->getTrace() as $step) {
637
			if (@$step['class'] . @$step['type'] . @$step['function'] !== 'Doctrine\Common\Annotations\DocParser->parse') {
638
				continue;
639
			}
640
641
			$context = Strings::match($step['args'][1], '~^(?P<type>[^\s]+)\s*(?P<class>[^:]+)(?:::\$?(?P<property>[^\\(]+))?$~i');
642
			break;
643
		}
644
645
		if (!isset($context)) {
646
			return FALSE;
647
		}
648
649
		$refl = Nette\Reflection\ClassType::from($context['class']);
650
		$file = $refl->getFileName();
651
		$line = NULL;
652
653
		if ($context['type'] === 'property') {
654
			$refl = $refl->getProperty($context['property']);
655
			$line = Kdyby\Doctrine\Helpers::getPropertyLine($refl);
656
657
		} elseif ($context['type'] === 'method') {
658
			$refl = $refl->getProperty($context['method']);
659
		}
660
661
		if (($errorLine = self::calculateErrorLine($refl, $e, $line)) === NULL) {
662
			return FALSE;
663
		}
664
665
		$dump = BlueScreen::highlightFile($file, $errorLine);
666
667
		return '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' . $dump;
668
	}
669
670
671
672
	/**
673
	 * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method|\Nette\Reflection\Property $refl
674
	 * @param \Exception|\Throwable $e
675
	 * @param int|NULL $startLine
676
	 * @return int|string|NULL
677
	 */
678
	public static function calculateErrorLine(\Reflector $refl, $e, $startLine = NULL)
679
	{
680
		if ($startLine === NULL && method_exists($refl, 'getStartLine')) {
681
			$startLine = $refl->getStartLine();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getStartLine() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
682
		}
683
		if ($startLine === NULL) {
684
			return NULL;
685
		}
686
687
		if ($pos = Strings::match($e->getMessage(), '~position\s*(\d+)~')) {
688
			$targetLine = self::calculateAffectedLine($refl, $pos[1]);
689
690
		} elseif ($notImported = Strings::match($e->getMessage(), '~^\[Semantical Error\]\s+The annotation "([^"]*?)"~i')) {
691
			$parts = explode(self::findRenamed($refl, $notImported[1]), self::cleanedPhpDoc($refl), 2);
692
			$targetLine = self::calculateAffectedLine($refl, strlen($parts[0]));
693
694
		} elseif ($notFound = Strings::match($e->getMessage(), '~^\[Semantical Error\]\s+Couldn\'t find\s+(.*?)\s+(.*?),\s+~')) {
695
			// this is just a guess
696
			$parts = explode(self::findRenamed($refl, $notFound[2]), self::cleanedPhpDoc($refl), 2);
697
			$targetLine = self::calculateAffectedLine($refl, strlen($parts[0]));
698
699
		} else {
700
			$targetLine = self::calculateAffectedLine($refl, 1);
701
		}
702
703
		$phpDocLines = count(Strings::split($refl->getDocComment(), '~[\n\r]+~'));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDocComment() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject, ReflectionProperty.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
704
705
		return $startLine - ($phpDocLines - ($targetLine - 1));
706
	}
707
708
709
710
	/**
711
	 * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method $refl
712
	 * @param int $symbolPos
713
	 *
714
	 * @return int
715
	 */
716
	protected static function calculateAffectedLine(\Reflector $refl, $symbolPos)
717
	{
718
		$doc = $refl->getDocComment();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDocComment() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject, ReflectionProperty.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
719
		$cleanedDoc = self::cleanedPhpDoc($refl, $atPos);
720
		$beforeCleanLines = count(Strings::split(substr($doc, 0, $atPos), '~[\n\r]+~'));
721
		$parsedDoc = substr($cleanedDoc, 0, $symbolPos + 1);
722
		$parsedLines = count(Strings::split($parsedDoc, '~[\n\r]+~'));
723
724
		return $parsedLines + max($beforeCleanLines - 1, 0);
725
	}
726
727
728
729
	/**
730
	 * @param \Reflector|Nette\Reflection\ClassType|Nette\Reflection\Method $refl
731
	 * @param $annotation
732
	 */
733
	private static function findRenamed(\Reflector $refl, $annotation)
734
	{
735
		$parser = new Doctrine\Common\Annotations\PhpParser();
736
		$imports = $parser->parseClass($refl instanceof \ReflectionClass ? $refl : $refl->getDeclaringClass());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDeclaringClass() does only exist in the following implementations of said interface: ReflectionMethod, ReflectionParameter, ReflectionProperty.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
737
738
		$annotationClass = ltrim($annotation, '@');
739
		foreach ($imports as $alias => $import) {
740
			if (!Strings::startsWith($annotationClass, $import)) {
741
				continue;
742
			}
743
744
			$aliased = str_replace(Strings::lower($import), $alias, Strings::lower($annotationClass));
745
			$searchFor = preg_quote(Strings::lower($aliased));
746
747
			if (!$m = Strings::match($refl->getDocComment(), "~(?P<usage>@?$searchFor)~i")) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDocComment() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject, ReflectionProperty.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
748
				continue;
749
			}
750
751
			return $m['usage'];
752
		}
753
754
		return $annotation;
755
	}
756
757
758
759
	/**
760
	 * @param \Nette\Reflection\ClassType|\Nette\Reflection\Method|\Reflector $refl
761
	 * @param null $atPos
762
	 *
763
	 * @return string
764
	 */
765
	private static function cleanedPhpDoc(\Reflector $refl, &$atPos = NULL)
766
	{
767
		return trim(substr($doc = $refl->getDocComment(), $atPos = strpos($doc, '@') - 1), '* /');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDocComment() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject, ReflectionProperty.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
768
	}
769
770
771
772
	/**
773
	 * Returns link to editor.
774
	 * @author David Grudl
775
	 * @param string $file
776
	 * @param string $line
777
	 * @param string $text
778
	 * @return Nette\Utils\Html
779
	 */
780
	private static function editorLink($file, $line, $text = NULL)
781
	{
782
		if (Debugger::$editor && is_file($file) && $text !== NULL) {
783
			return Nette\Utils\Html::el('a')
784
				->href(strtr(Debugger::$editor, ['%file' => rawurlencode($file), '%line' => $line]))
785
				->title("$file:$line")
786
				->setHtml($text);
787
788
		} else {
789
			return Helpers::editorLink($file, $line);
790
		}
791
	}
792
793
794
795
	/****************** Registration *********************/
796
797
798
799
	public function enableLogging()
800
	{
801
		if ($this->connection === NULL) {
802
			throw new Kdyby\Doctrine\InvalidStateException("Doctrine Panel is not bound to connection.");
803
		}
804
805
		$config = $this->connection->getConfiguration();
806
		$logger = $config->getSQLLogger();
807
808
		if ($logger instanceof Doctrine\DBAL\Logging\LoggerChain) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Logging\LoggerChain does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
809
			$logger->addLogger($this);
810
811
		} else {
812
			$config->setSQLLogger($this);
813
		}
814
	}
815
816
817
818
	/**
819
	 * @param \Doctrine\DBAL\Connection $connection
820
	 * @return Panel
821
	 */
822
	public function bindConnection(Doctrine\DBAL\Connection $connection)
823
	{
824
		if ($this->connection !== NULL) {
825
			throw new Kdyby\Doctrine\InvalidStateException("Doctrine Panel is already bound to connection.");
826
		}
827
828
		$this->connection = $connection;
829
830
		// Tracy
831
		$this->registerBarPanel(Debugger::getBar());
832
		Debugger::getBlueScreen()->addPanel([$this, 'renderQueryException']);
833
834
		return $this;
835
	}
836
837
838
839
	/**
840
	 * @param Doctrine\ORM\EntityManager $em
841
	 * @return Panel
842
	 */
843
	public function bindEntityManager(Doctrine\ORM\EntityManager $em)
844
	{
845
		$this->em = $em;
846
847
		if ($this->em instanceof Kdyby\Doctrine\EntityManager) {
848
			$uowPanel = new EntityManagerUnitOfWorkSnapshotPanel();
849
			$uowPanel->bindEntityManager($em);
850
		}
851
852
		if ($this->connection === NULL) {
853
			$this->bindConnection($em->getConnection());
854
		}
855
856
		return $this;
857
	}
858
859
860
861
	/**
862
	 * Registers panel to debugger
863
	 *
864
	 * @param \Tracy\Bar $bar
865
	 */
866
	public function registerBarPanel(Bar $bar)
867
	{
868
		$bar->addPanel($this);
869
	}
870
871
872
873
	/**
874
	 * Registers generic exception renderer
875
	 */
876
	public static function registerBluescreen(Nette\DI\Container $dic)
877
	{
878
		Debugger::getBlueScreen()->addPanel(function ($e) use ($dic) {
879
			return Panel::renderException($e, $dic);
880
		});
881
	}
882
883
}
884