Completed
Push — master ( 26da79...8decc6 )
by Jáchym
06:04 queued 04:34
created

Panel::enableLogging()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
rs 9.4285
cc 3
eloc 9
nc 3
nop 0
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 implements IBarPanel, Doctrine\DBAL\Logging\SQLLogger
39
{
40
41
	use \Kdyby\StrictObjects\Scream;
42
43
	use \Kdyby\StrictObjects\Scream;
44
45
	/**
46
	 * @var float logged time
47
	 */
48
	public $totalTime = 0;
49
50
	/**
51
	 * @var array
52
	 */
53
	public $queries = [];
54
55
	/**
56
	 * @var array
57
	 */
58
	public $failed = [];
59
60
	/**
61
	 * @var array
62
	 */
63
	public $skipPaths = [
64
		'vendor/nette/', 'src/Nette/',
65
		'vendor/doctrine/collections/', 'lib/Doctrine/Collections/',
66
		'vendor/doctrine/common/', 'lib/Doctrine/Common/',
67
		'vendor/doctrine/dbal/', 'lib/Doctrine/DBAL/',
68
		'vendor/doctrine/orm/', 'lib/Doctrine/ORM/',
69
		'vendor/kdyby/doctrine/', 'src/Kdyby/Doctrine/',
70
		'vendor/phpunit',
71
	];
72
73
	/**
74
	 * @var \Doctrine\DBAL\Connection
75
	 */
76
	private $connection;
77
78
	/**
79
	 * @var \Doctrine\ORM\EntityManager
80
	 */
81
	private $em;
82
83
84
85
	/***************** Doctrine\DBAL\Logging\SQLLogger ********************/
86
87
88
89
	/**
90
	 * @param string $sql
91
	 * @param array|null $params
92
	 * @param array|null $types
93
	 */
94
	public function startQuery($sql, array $params = NULL, array $types = NULL)
95
	{
96
		Debugger::timer('doctrine');
97
98
		$source = NULL;
99
		foreach (debug_backtrace(FALSE) as $row) {
100
			if (isset($row['file']) && $this->filterTracePaths(realpath($row['file']))) {
101
				if (isset($row['class']) && stripos($row['class'], '\\' . Proxy::MARKER) !== FALSE) {
102
					if (!in_array(Doctrine\Common\Persistence\Proxy::class, class_implements($row['class']))) {
103
						continue;
104
105
					} elseif (isset($row['function']) && $row['function'] === '__load') {
106
						continue;
107
					}
108
109
				} elseif (stripos($row['file'], DIRECTORY_SEPARATOR . Proxy::MARKER) !== FALSE) {
110
					continue;
111
				}
112
113
				$source = [$row['file'], (int) $row['line']];
114
				break;
115
			}
116
		}
117
118
		$this->queries[] = [$sql, $params, NULL, $types, $source];
119
	}
120
121
122
123
	/**
124
	 * @param string $file
125
	 * @return boolean
126
	 */
127
	protected function filterTracePaths($file)
128
	{
129
		$file = str_replace(DIRECTORY_SEPARATOR, '/', $file);
130
		$return = is_file($file);
131
		foreach ($this->skipPaths as $path) {
132
			if (!$return) {
133
				break;
134
			}
135
			$return = $return && strpos($file, '/' . trim($path, '/') . '/') === FALSE;
136
		}
137
		return $return;
138
	}
139
140
141
142
	/**
143
	 * @return array
144
	 */
145
	public function stopQuery()
146
	{
147
		$keys = array_keys($this->queries);
148
		$key = end($keys);
149
		$this->queries[$key][2] = $time = Debugger::timer('doctrine');
150
		$this->totalTime += $time;
151
152
		return $this->queries[$key] + array_fill_keys(range(0, 4), NULL);
153
	}
154
155
156
157
	/**
158
	 * @param \Exception|\Throwable $exception
159
	 */
160
	public function queryFailed($exception)
161
	{
162
		$this->failed[spl_object_hash($exception)] = $this->stopQuery();
163
	}
164
165
166
167
	/***************** Tracy\IBarPanel ********************/
168
169
170
171
	/**
172
	 * @return string
173
	 */
174
	public function getTab()
175
	{
176
		return '<span title="Doctrine 2">'
177
			. '<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>'
178
			. '<span class="tracy-label">'
179
			. count($this->queries) . ' queries'
180
			. ($this->totalTime ? ' / ' . sprintf('%0.1f', $this->totalTime * 1000) . ' ms' : '')
181
			. '</span>'
182
			. '</span>';
183
	}
184
185
186
187
	/**
188
	 * @return string
189
	 */
190
	public function getPanel()
191
	{
192
		if (empty($this->queries)) {
193
			return '';
194
		}
195
196
		$connParams = $this->connection->getParams();
197
		if ($connParams['driver'] === 'pdo_sqlite' && isset($connParams['path'])) {
198
			$host = 'path: ' . basename($connParams['path']);
199
200
		} else {
201
			$host = sprintf('host: %s%s/%s',
202
				$this->connection->getHost(),
203
				(($p = $this->connection->getPort()) ? ':' . $p : ''),
204
				$this->connection->getDatabase()
205
			);
206
		}
207
208
		return
209
			$this->renderStyles() .
210
			sprintf('<h1>Queries: %s %s, %s</h1>',
211
				count($this->queries),
212
				($this->totalTime ? ', time: ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms' : ''),
213
				$host
214
			) .
215
			'<div class="nette-inner tracy-inner nette-Doctrine2Panel">' .
216
				implode('<br>', array_filter([
217
					$this->renderPanelCacheStatistics(),
218
					$this->renderPanelQueries()
219
				])) .
220
			'</div>';
221
	}
222
223
224
225
	private function renderPanelCacheStatistics()
226
	{
227
		if (empty($this->em)) {
228
			return '';
229
		}
230
231
		$config = $this->em->getConfiguration();
232
		if (!$config->isSecondLevelCacheEnabled()) {
233
			return '';
234
		}
235
236
		$loggerChain = $config->getSecondLevelCacheConfiguration()
237
			->getCacheLogger();
238
239
		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...
240
			return '';
241
		}
242
243
		if (!$statistics = $loggerChain->getLogger('statistics')) {
244
			return '';
245
		}
246
247
		return Dumper::toHtml($statistics, [Dumper::DEPTH => 5]);
248
	}
249
250
251
252
	private function renderPanelQueries()
253
	{
254
		if (empty($this->queries)) {
255
			return "";
256
		}
257
258
		$s = "";
259
		foreach ($this->queries as $query) {
260
			$s .= $this->processQuery($query);
261
		}
262
263
		return '<table><tr><th>ms</th><th>SQL Statement</th></tr>' . $s . '</table>';
264
	}
265
266
267
268
	/**
269
	 * @return string
270
	 */
271
	protected function renderStyles()
272
	{
273
		return '<style>
274
			#nette-debug td.nette-Doctrine2Panel-sql { background: white !important}
275
			#nette-debug .nette-Doctrine2Panel-source { color: #BBB !important }
276
			#nette-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto }
277
			#tracy-debug td.nette-Doctrine2Panel-sql { background: white !important}
278
			#tracy-debug .nette-Doctrine2Panel-source { color: #BBB !important }
279
			#tracy-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto }
280
		</style>';
281
	}
282
283
284
285
	/**
286
	 * @param array $query
287
	 * @return string
288
	 */
289
	protected function processQuery(array $query)
290
	{
291
		$h = 'htmlspecialchars';
292
		list($sql, $params, $time, $types, $source) = $query;
293
294
		$s = self::highlightQuery(static::formatQuery($sql, (array) $params, (array) $types, $this->connection ? $this->connection->getDatabasePlatform() : NULL));
295
		if ($source) {
296
			$s .= self::editorLink($source[0], $source[1], $h('.../' . basename(dirname($source[0]))) . '/<b>' . $h(basename($source[0])) . '</b>');
297
		}
298
299
		return '<tr><td>' . sprintf('%0.3f', $time * 1000) . '</td>' .
300
			'<td class = "nette-Doctrine2Panel-sql">' . $s . '</td></tr>';
301
	}
302
303
304
305
	/****************** Exceptions handling *********************/
306
307
308
309
	/**
310
	 * @param \Exception|\Throwable $e
311
	 * @return array|NULL
312
	 */
313
	public function renderQueryException($e)
314
	{
315
		if ($e instanceof \PDOException && count($this->queries)) {
316
			$types = $params = [];
317
318
			if ($this->connection !== NULL) {
319
				if (!isset($this->failed[spl_object_hash($e)])) {
320
					return NULL;
321
				}
322
323
				list($sql, $params, , , $source) = $this->failed[spl_object_hash($e)];
324
325
			} else {
326
				list($sql, $params, , $types, $source) = end($this->queries) + range(1, 5);
327
			}
328
329
			if (!$sql) {
330
				return NULL;
331
			}
332
333
			return [
334
				'tab' => 'SQL',
335
				'panel' => $this->dumpQuery($sql, $params, $types, $source),
336
			];
337
338
		} elseif ($e instanceof Kdyby\Doctrine\QueryException && $e->query !== NULL) {
339
			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...
340
				return [
341
					'tab' => 'DQL',
342
					'panel' => $this->dumpQuery($e->query->getDQL(), $e->query->getParameters()),
343
				];
344
345
			} elseif ($e->query instanceof Kdyby\Doctrine\NativeQueryWrapper) {
346
				return [
347
					'tab' => 'Native SQL',
348
					'panel' => $this->dumpQuery($e->query->getSQL(), $e->query->getParameters()),
349
				];
350
			}
351
		}
352
353
		return NULL;
354
	}
355
356
357
358
	/**
359
	 * @param \Exception|\Throwable $e
360
	 * @param \Nette\DI\Container $dic
361
	 * @return array|NULL
362
	 */
363
	public static function renderException($e, Nette\DI\Container $dic)
364
	{
365
		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...
366
			if ($dump = self::highlightAnnotationLine($e)) {
367
				return [
368
					'tab' => 'Annotation',
369
					'panel' => $dump,
370
				];
371
			}
372
373
		} 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...
374
			if ($invalidEntity = Strings::match($e->getMessage(), '~^Class "([\\S]+)" .*? is not .*? valid~i')) {
375
				$refl = Nette\Reflection\ClassType::from($invalidEntity[1]);
376
				$file = $refl->getFileName();
377
				$errorLine = $refl->getStartLine();
378
379
				return [
380
					'tab' => 'Invalid entity',
381
					'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' .
382
						BlueScreen::highlightFile($file, $errorLine),
383
				];
384
			}
385
386
		} elseif ($e instanceof Doctrine\DBAL\Schema\SchemaException && $dic && ($em = $dic->getByType(Kdyby\Doctrine\EntityManager::class, 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...
387
			if (!$em instanceof Kdyby\Doctrine\EntityManager) {
388
				return null;
389
			}
390
391
			if ($invalidTable = Strings::match($e->getMessage(), '~table \'(.*?)\'~i')) {
392
				foreach ($em->getMetadataFactory()->getAllMetadata() as $class) {
393
					/** @var Kdyby\Doctrine\Mapping\ClassMetadata $class */
394
					if ($class->getTableName() === $invalidTable[1]) {
395
						$refl = $class->getReflectionClass();
396
						break;
397
					}
398
				}
399
400
				if (!isset($refl)) {
401
					return NULL;
402
				}
403
404
				$file = $refl->getFileName();
405
				$errorLine = $refl->getStartLine();
406
407
				return [
408
					'tab' => 'Invalid schema',
409
					'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' .
410
						BlueScreen::highlightFile($file, $errorLine),
411
				];
412
			}
413
414
		} elseif ($e instanceof Kdyby\Doctrine\DBALException && $e->query !== NULL) {
415
			return [
416
				'tab' => 'SQL',
417
				'panel' => self::highlightQuery(static::formatQuery($e->query, $e->params, [])),
418
			];
419
420
		} 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...
421
			if (($prev = $e->getPrevious()) && ($item = Helpers::findTrace($e->getTrace(), Doctrine\DBAL\DBALException::class . '::driverExceptionDuringQuery'))) {
422
				/** @var \Doctrine\DBAL\Driver $driver */
423
				$driver = $item['args'][0];
424
				$params = isset($item['args'][3]) ? $item['args'][3] : [];
425
426
				return [
427
					'tab' => 'SQL',
428
					'panel' => self::highlightQuery(static::formatQuery($item['args'][2], $params, [], $driver->getDatabasePlatform())),
429
				];
430
			}
431
432
		} 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...
433
			if (($prev = $e->getPrevious()) && preg_match('~^(SELECT|INSERT|UPDATE|DELETE)\s+.*~i', $prev->getMessage())) {
434
				return [
435
					'tab' => 'DQL',
436
					'panel' => self::highlightQuery(static::formatQuery($prev->getMessage(), [], [])),
437
				];
438
			}
439
440
		} elseif ($e instanceof \PDOException) {
441
			$params = [];
442
443
			if (isset($e->queryString)) {
444
				$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...
445
446
			} elseif ($item = Helpers::findTrace($e->getTrace(), Doctrine\DBAL\Connection::class . '::executeQuery')) {
447
				$sql = $item['args'][0];
448
				$params = $item['args'][1];
449
450
			} elseif ($item = Helpers::findTrace($e->getTrace(), \PDO::class . '::query')) {
451
				$sql = $item['args'][0];
452
453
			} elseif ($item = Helpers::findTrace($e->getTrace(), \PDO::class . '::prepare')) {
454
				$sql = $item['args'][0];
455
			}
456
457
			return isset($sql) ? [
458
				'tab' => 'SQL',
459
				'panel' => self::highlightQuery(static::formatQuery($sql, $params, [])),
460
			] : NULL;
461
		}
462
463
		return NULL;
464
	}
465
466
467
468
	/**
469
	 * @param string $query
470
	 * @param array|Doctrine\Common\Collections\ArrayCollection $params
471
	 * @param array $types
472
	 * @param array|string $source
473
	 * @return string
474
	 */
475
	protected function dumpQuery($query, $params, array $types = [], $source = NULL)
476
	{
477
		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...
478
			$tmp = [];
479
			$tmpTypes = [];
480
			foreach ($params as $key => $param) {
481
				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...
482
					$tmpTypes[$param->getName()] = $param->getType();
483
					$tmp[$param->getName()] = $param->getValue();
484
					continue;
485
				}
486
				$tmp[$key] = $param;
487
			}
488
			$params = $tmp;
489
			$types = $tmpTypes;
490
		}
491
492
		// query
493
		$s = '<p><b>Query</b></p><table><tr><td class="nette-Doctrine2Panel-sql">';
494
		$s .= self::highlightQuery(static::formatQuery($query, $params, $types, $this->connection ? $this->connection->getDatabasePlatform() : NULL));
495
		$s .= '</td></tr></table>';
496
497
		$e = NULL;
498
		if ($source && is_array($source)) {
499
			list($file, $line) = $source;
500
			$e = '<p><b>File:</b> ' . self::editorLink($file, $line) . '</p>';
501
		}
502
503
		// styles and dump
504
		return $this->renderStyles() . '<div class="nette-inner tracy-inner nette-Doctrine2Panel">' . $e . $s . '</div>';
505
	}
506
507
508
509
	/**
510
	 * Returns syntax highlighted SQL command.
511
	 * This method is same as Nette\Database\Helpers::dumpSql except for parameters handling.
512
	 * @link https://github.com/nette/database/blob/667143b2d5b940f78c8dc9212f95b1bbc033c6a3/src/Database/Helpers.php#L75-L138
513
	 * @author David Grudl
514
	 * @param string $sql
515
	 * @return string
516
	 */
517
	public static function highlightQuery($sql)
518
	{
519
		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';
520
		static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE|WITH|INSTANCE\s+OF';
521
522
		// insert new lines
523
		$sql = " $sql ";
524
		$sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
525
526
		// reduce spaces
527
		$sql = preg_replace('#[ \t]{2,}#', ' ', $sql);
528
529
		$sql = wordwrap($sql, 100);
530
		$sql = preg_replace('#([ \t]*\r?\n){2,}#', "\n", $sql);
531
532
		// syntax highlight
533
		$sql = htmlspecialchars($sql, ENT_IGNORE, 'UTF-8');
534
		$sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function ($matches) {
535
			if (!empty($matches[1])) { // comment
536
				return '<em style="color:gray">' . $matches[1] . '</em>';
537
538
			} elseif (!empty($matches[2])) { // error
539
				return '<strong style="color:red">' . $matches[2] . '</strong>';
540
541
			} elseif (!empty($matches[3])) { // most important keywords
542
				return '<strong style="color:blue">' . $matches[3] . '</strong>';
543
544
			} elseif (!empty($matches[4])) { // other keywords
545
				return '<strong style="color:green">' . $matches[4] . '</strong>';
546
			}
547
		}, $sql);
548
549
		return '<pre class="dump">' . trim($sql) . "</pre>\n";
550
	}
551
552
553
554
	/**
555
	 * @param string $query
556
	 * @param array $params
557
	 * @param array $types
558
	 * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
559
	 * @throws \Doctrine\DBAL\DBALException
560
	 * @throws \Nette\Utils\RegexpException
561
	 * @return string
562
	 */
563
	public static function formatQuery($query, $params, array $types = [], AbstractPlatform $platform = NULL)
564
	{
565
		if ($platform === NULL) {
566
			$platform = new Doctrine\DBAL\Platforms\MySqlPlatform();
567
		}
568
569
		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...
570
			foreach ($params as $key => $param) {
571
				if (is_array($param)) {
572
					$types[$key] = Doctrine\DBAL\Connection::PARAM_STR_ARRAY;
573
574
				} else {
575
					$types[$key] = 'string';
576
				}
577
			}
578
		}
579
580
		try {
581
			list($query, $params, $types) = \Doctrine\DBAL\SQLParserUtils::expandListParameters($query, $params, $types);
582
		} 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...
583
		}
584
585
		$formattedParams = [];
586
		foreach ($params as $key => $param) {
587
			if (isset($types[$key])) {
588
				if (is_scalar($types[$key]) && array_key_exists($types[$key], Type::getTypesMap())) {
589
					$types[$key] = Type::getType($types[$key]);
590
				}
591
592
				/** @var Type[] $types */
593
				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...
594
					$param = $types[$key]->convertToDatabaseValue($param, $platform);
595
				}
596
			}
597
598
			$formattedParams[] = SimpleParameterFormatter::format($param);
599
		}
600
		$params = $formattedParams;
601
602
		if (Nette\Utils\Validators::isList($params)) {
603
			$parts = explode('?', $query);
604
			if (count($params) > $parts) {
605
				throw new Kdyby\Doctrine\InvalidStateException("Too mny parameters passed to query.");
606
			}
607
608
			return implode('', Kdyby\Doctrine\Helpers::zipper($parts, $params));
609
		}
610
611
		return Strings::replace($query, '~(\\:[a-z][a-z0-9]*|\\?[0-9]*)~i', function ($m) use (&$params) {
612
			if (substr($m[0], 0, 1) === '?') {
613
				if (strlen($m[0]) > 1) {
614
					if (isset($params[$k = substr($m[0], 1)])) {
615
						return $params[$k];
616
					}
617
618
				} else {
619
					return array_shift($params);
620
				}
621
622
			} else {
623
				if (isset($params[$k = substr($m[0], 1)])) {
624
					return $params[$k];
625
				}
626
			}
627
628
			return $m[0];
629
		});
630
	}
631
632
633
634
	/**
635
	 * @param \Doctrine\Common\Annotations\AnnotationException $e
636
	 * @return string|bool
637
	 */
638
	public static function highlightAnnotationLine(AnnotationException $e)
639
	{
640
		foreach ($e->getTrace() as $step) {
641
			if (@$step['class'] . @$step['type'] . @$step['function'] !== Doctrine\Common\Annotations\DocParser::class . '->parse') {
642
				continue;
643
			}
644
645
			$context = Strings::match($step['args'][1], '~^(?P<type>[^\s]+)\s*(?P<class>[^:]+)(?:::\$?(?P<property>[^\\(]+))?$~i');
646
			break;
647
		}
648
649
		if (!isset($context)) {
650
			return FALSE;
651
		}
652
653
		$refl = Nette\Reflection\ClassType::from($context['class']);
654
		$file = $refl->getFileName();
655
		$line = NULL;
656
657
		if ($context['type'] === 'property') {
658
			$refl = $refl->getProperty($context['property']);
659
			$line = Kdyby\Doctrine\Helpers::getPropertyLine($refl);
660
661
		} elseif ($context['type'] === 'method') {
662
			$refl = $refl->getProperty($context['method']);
663
		}
664
665
		$errorLine = self::calculateErrorLine($refl, $e, $line);
666
		if ($errorLine === NULL) {
667
			return FALSE;
668
		}
669
670
		$dump = BlueScreen::highlightFile($file, $errorLine);
671
672
		return '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' . $dump;
673
	}
674
675
676
677
	/**
678
	 * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method|\Nette\Reflection\Property $refl
679
	 * @param \Exception|\Throwable $e
680
	 * @param int|NULL $startLine
681
	 * @return int|NULL
682
	 */
683
	public static function calculateErrorLine(\Reflector $refl, $e, $startLine = NULL)
684
	{
685
		if ($startLine === NULL && method_exists($refl, 'getStartLine')) {
686
			$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...
687
		}
688
		if ($startLine === NULL) {
689
			return NULL;
690
		}
691
692
		if ($pos = Strings::match($e->getMessage(), '~position\s*(\d+)~')) {
693
			$targetLine = self::calculateAffectedLine($refl, $pos[1]);
694
695
		} elseif ($notImported = Strings::match($e->getMessage(), '~^\[Semantical Error\]\s+The annotation "([^"]*?)"~i')) {
696
			$parts = explode(self::findRenamed($refl, $notImported[1]), self::cleanedPhpDoc($refl), 2);
697
			$targetLine = self::calculateAffectedLine($refl, strlen($parts[0]));
698
699
		} elseif ($notFound = Strings::match($e->getMessage(), '~^\[Semantical Error\]\s+Couldn\'t find\s+(.*?)\s+(.*?),\s+~')) {
700
			// this is just a guess
701
			$parts = explode(self::findRenamed($refl, $notFound[2]), self::cleanedPhpDoc($refl), 2);
702
			$targetLine = self::calculateAffectedLine($refl, strlen($parts[0]));
703
704
		} else {
705
			$targetLine = self::calculateAffectedLine($refl, 1);
706
		}
707
708
		$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...
709
710
		return $startLine - ($phpDocLines - ($targetLine - 1));
711
	}
712
713
714
715
	/**
716
	 * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method $refl
717
	 * @param int $symbolPos
718
	 * @return int
719
	 */
720
	protected static function calculateAffectedLine(\Reflector $refl, $symbolPos)
721
	{
722
		$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...
723
		/** @var int|NULL $atPos */
724
		$atPos = NULL;
725
		$cleanedDoc = self::cleanedPhpDoc($refl, $atPos);
726
		$beforeCleanLines = count(Strings::split(substr($doc, 0, $atPos), '~[\n\r]+~'));
727
		$parsedDoc = substr($cleanedDoc, 0, $symbolPos + 1);
728
		$parsedLines = count(Strings::split($parsedDoc, '~[\n\r]+~'));
729
730
		return $parsedLines + max($beforeCleanLines - 1, 0);
731
	}
732
733
734
735
	/**
736
	 * @param \Reflector|Nette\Reflection\ClassType|Nette\Reflection\Method $refl
737
	 * @param string $annotation
738
	 * @return string
739
	 */
740
	private static function findRenamed(\Reflector $refl, $annotation)
741
	{
742
		$parser = new Doctrine\Common\Annotations\PhpParser();
743
		$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...
744
745
		$annotationClass = ltrim($annotation, '@');
746
		foreach ($imports as $alias => $import) {
747
			if (!Strings::startsWith($annotationClass, $import)) {
748
				continue;
749
			}
750
751
			$aliased = str_replace(Strings::lower($import), $alias, Strings::lower($annotationClass));
752
			$searchFor = preg_quote(Strings::lower($aliased));
753
754
			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...
755
				continue;
756
			}
757
758
			return $m['usage'];
759
		}
760
761
		return $annotation;
762
	}
763
764
765
766
	/**
767
	 * @param \Nette\Reflection\ClassType|\Nette\Reflection\Method|\Reflector $refl
768
	 * @param int|null $atPos
769
	 * @return string
770
	 */
771
	private static function cleanedPhpDoc(\Reflector $refl, &$atPos = NULL)
772
	{
773
		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...
774
	}
775
776
777
778
	/**
779
	 * Returns link to editor.
780
	 * @author David Grudl
781
	 * @param string $file
782
	 * @param string|int $line
783
	 * @param string $text
784
	 * @return Nette\Utils\Html
785
	 */
786
	private static function editorLink($file, $line, $text = NULL)
787
	{
788
		if (Debugger::$editor && is_file($file) && $text !== NULL) {
789
			return Nette\Utils\Html::el('a')
790
				->href(strtr(Debugger::$editor, ['%file' => rawurlencode($file), '%line' => $line]))
791
				->setAttribute('title', "$file:$line")
792
				->setHtml($text);
793
794
		} else {
795
			return Nette\Utils\Html::el()->setHtml(Helpers::editorLink($file, $line));
796
		}
797
	}
798
799
800
801
	/****************** Registration *********************/
802
803
804
805
	public function enableLogging()
806
	{
807
		if ($this->connection === NULL) {
808
			throw new Kdyby\Doctrine\InvalidStateException("Doctrine Panel is not bound to connection.");
809
		}
810
811
		$config = $this->connection->getConfiguration();
812
		$logger = $config->getSQLLogger();
813
814
		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...
815
			$logger->addLogger($this);
816
817
		} else {
818
			$config->setSQLLogger($this);
819
		}
820
	}
821
822
823
824
	/**
825
	 * @param \Doctrine\DBAL\Connection $connection
826
	 * @return Panel
827
	 */
828
	public function bindConnection(Doctrine\DBAL\Connection $connection)
829
	{
830
		if ($this->connection !== NULL) {
831
			throw new Kdyby\Doctrine\InvalidStateException("Doctrine Panel is already bound to connection.");
832
		}
833
834
		$this->connection = $connection;
835
836
		// Tracy
837
		$this->registerBarPanel(Debugger::getBar());
838
		Debugger::getBlueScreen()->addPanel([$this, 'renderQueryException']);
839
840
		return $this;
841
	}
842
843
844
845
	/**
846
	 * @param Doctrine\ORM\EntityManager $em
847
	 * @return Panel
848
	 */
849
	public function bindEntityManager(Doctrine\ORM\EntityManager $em)
850
	{
851
		$this->em = $em;
852
853
		if ($this->em instanceof Kdyby\Doctrine\EntityManager) {
854
			$uowPanel = new EntityManagerUnitOfWorkSnapshotPanel();
855
			$uowPanel->bindEntityManager($em);
856
		}
857
858
		if ($this->connection === NULL) {
859
			$this->bindConnection($em->getConnection());
860
		}
861
862
		return $this;
863
	}
864
865
866
867
	/**
868
	 * Registers panel to debugger
869
	 *
870
	 * @param \Tracy\Bar $bar
871
	 */
872
	public function registerBarPanel(Bar $bar)
873
	{
874
		$bar->addPanel($this);
875
	}
876
877
878
879
	/**
880
	 * Registers generic exception renderer
881
	 */
882
	public static function registerBluescreen(Nette\DI\Container $dic)
883
	{
884
		Debugger::getBlueScreen()->addPanel(function ($e) use ($dic) {
885
			return Panel::renderException($e, $dic);
886
		});
887
	}
888
889
}
890