Complex classes like Panel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Panel, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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 | * @var array |
||
81 | */ |
||
82 | private $whitelistExceptions = []; |
||
83 | |||
84 | /** |
||
85 | * @var Doctrine\ORM\UnitOfWork |
||
86 | */ |
||
87 | private $unitOfWorkSnapshot; |
||
88 | |||
89 | |||
90 | |||
91 | public function markExceptionOwner(Doctrine\ORM\EntityManager $em, $exception) |
||
92 | { |
||
93 | if ($this->em !== $em) { |
||
94 | return; |
||
95 | } |
||
96 | |||
97 | $this->whitelistExceptions[] = $exception; |
||
98 | } |
||
99 | |||
100 | |||
101 | |||
102 | public function snapshotUnitOfWork(Doctrine\ORM\EntityManager $em) |
||
103 | { |
||
104 | if ($this->em !== $em) { |
||
105 | return; |
||
106 | } |
||
107 | |||
108 | $this->unitOfWorkSnapshot = clone $em->getUnitOfWork(); |
||
109 | } |
||
110 | |||
111 | |||
112 | |||
113 | /***************** Doctrine\DBAL\Logging\SQLLogger ********************/ |
||
114 | |||
115 | |||
116 | |||
117 | /** |
||
118 | * @param string |
||
119 | * @param array |
||
120 | * @param array |
||
121 | */ |
||
122 | public function startQuery($sql, array $params = NULL, array $types = NULL) |
||
123 | { |
||
124 | Debugger::timer('doctrine'); |
||
125 | |||
126 | $source = NULL; |
||
127 | foreach (debug_backtrace(FALSE) as $row) { |
||
128 | if (isset($row['file']) && $this->filterTracePaths(realpath($row['file']))) { |
||
129 | if (isset($row['class']) && stripos($row['class'], '\\' . Proxy::MARKER) !== FALSE) { |
||
130 | if (!in_array('Doctrine\Common\Persistence\Proxy', class_implements($row['class']))) { |
||
131 | continue; |
||
132 | |||
133 | } elseif (isset($row['function']) && $row['function'] === '__load') { |
||
134 | continue; |
||
135 | } |
||
136 | |||
137 | } elseif (stripos($row['file'], DIRECTORY_SEPARATOR . Proxy::MARKER) !== FALSE) { |
||
138 | continue; |
||
139 | } |
||
140 | |||
141 | $source = [$row['file'], (int) $row['line']]; |
||
142 | break; |
||
143 | } |
||
144 | } |
||
145 | |||
146 | $this->queries[] = [$sql, $params, NULL, $types, $source]; |
||
147 | } |
||
148 | |||
149 | |||
150 | |||
151 | /** |
||
152 | * @param string $file |
||
153 | * @return boolean |
||
154 | */ |
||
155 | protected function filterTracePaths($file) |
||
167 | |||
168 | |||
169 | |||
170 | /** |
||
171 | * @return array |
||
172 | */ |
||
173 | public function stopQuery() |
||
182 | |||
183 | |||
184 | |||
185 | /** |
||
186 | * @param \Exception|\Throwable $exception |
||
187 | */ |
||
188 | public function queryFailed($exception) |
||
192 | |||
193 | |||
194 | |||
195 | /***************** Tracy\IBarPanel ********************/ |
||
196 | |||
197 | |||
198 | |||
199 | /** |
||
200 | * @return string |
||
201 | */ |
||
202 | public function getTab() |
||
203 | { |
||
204 | return '<span title="Doctrine 2">' |
||
205 | . '<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>' |
||
206 | . '<span class="tracy-label">' |
||
207 | . count($this->queries) . ' queries' |
||
208 | . ($this->totalTime ? ' / ' . sprintf('%0.1f', $this->totalTime * 1000) . ' ms' : '') |
||
209 | . '</span>' |
||
210 | . '</span>'; |
||
211 | } |
||
212 | |||
213 | |||
214 | |||
215 | /** |
||
216 | * @return string |
||
217 | */ |
||
218 | public function getPanel() |
||
219 | { |
||
220 | if (empty($this->queries)) { |
||
221 | return ''; |
||
222 | } |
||
223 | |||
224 | $connParams = $this->connection->getParams(); |
||
225 | if ($connParams['driver'] === 'pdo_sqlite' && isset($connParams['path'])) { |
||
226 | $host = 'path: ' . basename($connParams['path']); |
||
227 | |||
228 | } else { |
||
229 | $host = sprintf('host: %s%s/%s', |
||
230 | $this->connection->getHost(), |
||
231 | (($p = $this->connection->getPort()) ? ':' . $p : ''), |
||
232 | $this->connection->getDatabase() |
||
233 | ); |
||
234 | } |
||
235 | |||
236 | return |
||
237 | $this->renderStyles() . |
||
238 | sprintf('<h1>Queries: %s %s, %s</h1>', |
||
239 | count($this->queries), |
||
240 | ($this->totalTime ? ', time: ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms' : ''), |
||
241 | $host |
||
242 | ) . |
||
243 | '<div class="nette-inner tracy-inner nette-Doctrine2Panel">' . |
||
244 | implode('<br>', array_filter([ |
||
245 | $this->renderPanelCacheStatistics(), |
||
246 | $this->renderPanelQueries() |
||
247 | ])) . |
||
248 | '</div>'; |
||
249 | } |
||
250 | |||
251 | |||
252 | |||
253 | private function renderPanelCacheStatistics() |
||
254 | { |
||
255 | if (empty($this->em)) { |
||
256 | return ''; |
||
257 | } |
||
258 | |||
259 | $config = $this->em->getConfiguration(); |
||
260 | if (!$config->isSecondLevelCacheEnabled()) { |
||
261 | return ''; |
||
262 | } |
||
263 | |||
264 | $loggerChain = $config->getSecondLevelCacheConfiguration() |
||
265 | ->getCacheLogger(); |
||
266 | |||
267 | if (!$loggerChain instanceof Doctrine\ORM\Cache\Logging\CacheLoggerChain) { |
||
|
|||
268 | return ''; |
||
269 | } |
||
270 | |||
271 | if (!$statistics = $loggerChain->getLogger('statistics')) { |
||
272 | return ''; |
||
273 | } |
||
274 | |||
275 | return Dumper::toHtml($statistics, [Dumper::DEPTH => 5]); |
||
276 | } |
||
277 | |||
278 | |||
279 | |||
280 | private function renderPanelQueries() |
||
281 | { |
||
282 | if (empty($this->queries)) { |
||
283 | return ""; |
||
284 | } |
||
285 | |||
286 | $s = ""; |
||
287 | foreach ($this->queries as $query) { |
||
288 | $s .= $this->processQuery($query); |
||
289 | } |
||
290 | |||
291 | return '<table><tr><th>ms</th><th>SQL Statement</th></tr>' . $s . '</table>'; |
||
292 | } |
||
293 | |||
294 | |||
295 | |||
296 | /** |
||
297 | * @return string |
||
298 | */ |
||
299 | protected function renderStyles() |
||
300 | { |
||
301 | return '<style> |
||
302 | #nette-debug td.nette-Doctrine2Panel-sql { background: white !important} |
||
303 | #nette-debug .nette-Doctrine2Panel-source { color: #BBB !important } |
||
304 | #nette-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto } |
||
305 | #tracy-debug td.nette-Doctrine2Panel-sql { background: white !important} |
||
306 | #tracy-debug .nette-Doctrine2Panel-source { color: #BBB !important } |
||
307 | #tracy-debug nette-Doctrine2Panel tr table { margin: 8px 0; max-height: 150px; overflow:auto } |
||
308 | </style>'; |
||
309 | } |
||
310 | |||
311 | |||
312 | |||
313 | /** |
||
314 | * @param array |
||
315 | * @return string |
||
316 | */ |
||
317 | protected function processQuery(array $query) |
||
330 | |||
331 | |||
332 | |||
333 | /****************** Exceptions handling *********************/ |
||
334 | |||
335 | |||
336 | |||
337 | /** |
||
338 | * @param \Exception|\Throwable $e |
||
339 | * @return void|array |
||
340 | */ |
||
341 | public function renderQueryException($e) |
||
342 | { |
||
343 | if ($e instanceof \PDOException && count($this->queries)) { |
||
344 | $types = $params = []; |
||
345 | |||
346 | if ($this->connection !== NULL) { |
||
347 | if (!$e instanceof Kdyby\Doctrine\DBALException || $e->connection !== $this->connection) { |
||
348 | return NULL; |
||
349 | |||
350 | } elseif (!isset($this->failed[spl_object_hash($e)])) { |
||
351 | return NULL; |
||
352 | } |
||
353 | |||
354 | list($sql, $params, , , $source) = $this->failed[spl_object_hash($e)]; |
||
355 | |||
356 | } else { |
||
357 | list($sql, $params, , $types, $source) = end($this->queries) + range(1, 5); |
||
358 | } |
||
359 | |||
360 | if (!$sql) { |
||
361 | return NULL; |
||
362 | } |
||
363 | |||
364 | return [ |
||
365 | 'tab' => 'SQL', |
||
366 | 'panel' => $this->dumpQuery($sql, $params, $types, $source), |
||
367 | ]; |
||
368 | |||
369 | } elseif ($e instanceof Kdyby\Doctrine\QueryException && $e->query !== NULL) { |
||
370 | if ($e->query instanceof Doctrine\ORM\Query) { |
||
371 | return [ |
||
372 | 'tab' => 'DQL', |
||
373 | 'panel' => $this->dumpQuery($e->query->getDQL(), $e->query->getParameters()), |
||
374 | ]; |
||
375 | |||
376 | } elseif ($e->query instanceof Kdyby\Doctrine\NativeQueryWrapper) { |
||
377 | return [ |
||
378 | 'tab' => 'Native SQL', |
||
379 | 'panel' => $this->dumpQuery($e->query->getSQL(), $e->query->getParameters()), |
||
380 | ]; |
||
381 | } |
||
382 | } |
||
383 | } |
||
384 | |||
385 | |||
386 | |||
387 | /** |
||
388 | * @param \Exception|\Throwable $e |
||
389 | * @param \Nette\DI\Container $dic |
||
390 | * @return array |
||
391 | */ |
||
392 | public function renderEntityManagerException($e) |
||
393 | { |
||
394 | if (!in_array($e, $this->whitelistExceptions, TRUE)) { |
||
395 | return NULL; // ignore |
||
396 | } |
||
397 | |||
398 | if (strpos(get_class($e), 'Doctrine\\ORM\\') !== FALSE && Helpers::findTrace($e->getTrace(), 'Doctrine\ORM\EntityManager::flush')) { |
||
399 | $UoW = $this->unitOfWorkSnapshot ?: $this->em->getUnitOfWork(); |
||
400 | |||
401 | $panel = '<div class="inner"><p><b>IdentityMap</b></p>' . |
||
402 | Dumper::toHtml($UoW->getIdentityMap(), [Dumper::COLLAPSE => TRUE]) . |
||
403 | '</div>'; |
||
404 | |||
405 | if ($scheduled = $UoW->getScheduledEntityInsertions()) { |
||
406 | $panel .= '<div class="inner"><p><b>Scheduled entity insertions</b></p>' . |
||
407 | Dumper::toHtml($scheduled, [Dumper::COLLAPSE => TRUE]) . |
||
408 | '</div>'; |
||
409 | } |
||
410 | |||
411 | if ($scheduled = $UoW->getScheduledEntityDeletions()) { |
||
412 | $panel .= '<div class="inner"><p><b>Scheduled entity deletions</b></p>' . |
||
413 | Dumper::toHtml($scheduled, [Dumper::COLLAPSE => TRUE]) . |
||
414 | '</div>'; |
||
415 | } |
||
416 | |||
417 | if ($scheduled = $UoW->getScheduledEntityUpdates()) { |
||
418 | $panel .= '<div class="inner"><p><b>Scheduled entity updates</b></p>' . |
||
419 | Dumper::toHtml($scheduled, [Dumper::COLLAPSE => TRUE]) . |
||
420 | '</div>'; |
||
421 | } |
||
422 | |||
423 | return [ |
||
424 | 'tab' => 'Doctrine\\ORM\\UnitOfWork', |
||
425 | 'panel' => $panel, |
||
426 | ]; |
||
427 | } |
||
428 | } |
||
429 | |||
430 | |||
431 | |||
432 | /** |
||
433 | * @param \Exception|\Throwable $e |
||
434 | * @param \Nette\DI\Container $dic |
||
435 | * @return array |
||
436 | */ |
||
437 | public static function renderException($e, Nette\DI\Container $dic) |
||
438 | { |
||
439 | if ($e instanceof AnnotationException) { |
||
440 | if ($dump = self::highlightAnnotationLine($e)) { |
||
441 | return [ |
||
442 | 'tab' => 'Annotation', |
||
443 | 'panel' => $dump, |
||
444 | ]; |
||
445 | } |
||
446 | |||
447 | } elseif ($e instanceof Doctrine\ORM\Mapping\MappingException) { |
||
448 | if ($invalidEntity = Strings::match($e->getMessage(), '~^Class "([\\S]+)" .*? is not .*? valid~i')) { |
||
449 | $refl = Nette\Reflection\ClassType::from($invalidEntity[1]); |
||
450 | $file = $refl->getFileName(); |
||
451 | $errorLine = $refl->getStartLine(); |
||
452 | |||
453 | return [ |
||
454 | 'tab' => 'Invalid entity', |
||
455 | 'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' . |
||
456 | BlueScreen::highlightFile($file, $errorLine), |
||
457 | ]; |
||
458 | } |
||
459 | |||
460 | } elseif ($e instanceof Doctrine\DBAL\Schema\SchemaException && $dic && ($em = $dic->getByType('Kdyby\Doctrine\EntityManager', FALSE))) { |
||
461 | /** @var Kdyby\Doctrine\EntityManager $em */ |
||
462 | |||
463 | if ($invalidTable = Strings::match($e->getMessage(), '~table \'(.*?)\'~i')) { |
||
464 | foreach ($em->getMetadataFactory()->getAllMetadata() as $class) { |
||
465 | /** @var Kdyby\Doctrine\Mapping\ClassMetadata $class */ |
||
466 | if ($class->getTableName() === $invalidTable[1]) { |
||
467 | $refl = $class->getReflectionClass(); |
||
468 | break; |
||
469 | } |
||
470 | } |
||
471 | |||
472 | if (!isset($refl)) { |
||
473 | return NULL; |
||
474 | } |
||
475 | |||
476 | $file = $refl->getFileName(); |
||
477 | $errorLine = $refl->getStartLine(); |
||
478 | |||
479 | return [ |
||
480 | 'tab' => 'Invalid schema', |
||
481 | 'panel' => '<p><b>File:</b> ' . self::editorLink($file, $errorLine) . '</p>' . |
||
482 | BlueScreen::highlightFile($file, $errorLine), |
||
483 | ]; |
||
484 | } |
||
485 | |||
486 | } elseif ($e instanceof Kdyby\Doctrine\DBALException && $e->query) { |
||
487 | return [ |
||
488 | 'tab' => 'SQL', |
||
489 | 'panel' => self::highlightQuery(static::formatQuery($e->query, $e->params, [])), |
||
490 | ]; |
||
491 | |||
492 | } elseif ($e instanceof Doctrine\DBAL\Exception\DriverException) { |
||
493 | if (($prev = $e->getPrevious()) && ($item = Helpers::findTrace($e->getTrace(), 'Doctrine\DBAL\DBALException::driverExceptionDuringQuery'))) { |
||
494 | /** @var \Doctrine\DBAL\Driver $driver */ |
||
495 | $driver = $item['args'][0]; |
||
496 | $params = isset($item['args'][3]) ? $item['args'][3] : []; |
||
497 | |||
498 | return [ |
||
499 | 'tab' => 'SQL', |
||
500 | 'panel' => self::highlightQuery(static::formatQuery($item['args'][2], $params, [], $driver->getDatabasePlatform())), |
||
501 | ]; |
||
502 | } |
||
503 | |||
504 | } elseif ($e instanceof Doctrine\ORM\Query\QueryException) { |
||
505 | if (($prev = $e->getPrevious()) && preg_match('~^(SELECT|INSERT|UPDATE|DELETE)\s+.*~i', $prev->getMessage())) { |
||
506 | return [ |
||
507 | 'tab' => 'DQL', |
||
508 | 'panel' => self::highlightQuery(static::formatQuery($prev->getMessage(), [], [])), |
||
509 | ]; |
||
510 | } |
||
511 | |||
512 | } elseif ($e instanceof \PDOException) { |
||
513 | $params = []; |
||
514 | |||
515 | if (isset($e->queryString)) { |
||
516 | $sql = $e->queryString; |
||
517 | |||
518 | } elseif ($item = Helpers::findTrace($e->getTrace(), 'Doctrine\DBAL\Connection::executeQuery')) { |
||
519 | $sql = $item['args'][0]; |
||
520 | $params = $item['args'][1]; |
||
521 | |||
522 | } elseif ($item = Helpers::findTrace($e->getTrace(), 'PDO::query')) { |
||
523 | $sql = $item['args'][0]; |
||
524 | |||
525 | } elseif ($item = Helpers::findTrace($e->getTrace(), 'PDO::prepare')) { |
||
526 | $sql = $item['args'][0]; |
||
527 | } |
||
528 | |||
529 | return isset($sql) ? [ |
||
530 | 'tab' => 'SQL', |
||
531 | 'panel' => self::highlightQuery(static::formatQuery($sql, $params, [])), |
||
532 | ] : NULL; |
||
533 | } |
||
534 | |||
535 | return NULL; |
||
536 | } |
||
537 | |||
538 | |||
539 | |||
540 | /** |
||
541 | * @param string $query |
||
542 | * @param array|Doctrine\Common\Collections\ArrayCollection $params |
||
543 | * @param array $types |
||
544 | * @param string $source |
||
545 | * |
||
546 | * @return array |
||
547 | */ |
||
548 | protected function dumpQuery($query, $params, array $types = [], $source = NULL) |
||
549 | { |
||
550 | if ($params instanceof ArrayCollection) { |
||
551 | $tmp = []; |
||
552 | $tmpTypes = []; |
||
553 | foreach ($params as $key => $param) { |
||
554 | if ($param instanceof Doctrine\ORM\Query\Parameter) { |
||
555 | $tmpTypes[$param->getName()] = $param->getType(); |
||
556 | $tmp[$param->getName()] = $param->getValue(); |
||
557 | continue; |
||
558 | } |
||
559 | $tmp[$key] = $param; |
||
560 | } |
||
561 | $params = $tmp; |
||
562 | $types = $tmpTypes; |
||
563 | } |
||
564 | |||
565 | // query |
||
566 | $s = '<p><b>Query</b></p><table><tr><td class="nette-Doctrine2Panel-sql">'; |
||
567 | $s .= self::highlightQuery(static::formatQuery($query, $params, $types, $this->connection ? $this->connection->getDatabasePlatform() : NULL)); |
||
568 | $s .= '</td></tr></table>'; |
||
569 | |||
570 | $e = NULL; |
||
571 | if ($source && is_array($source)) { |
||
572 | list($file, $line) = $source; |
||
573 | $e = '<p><b>File:</b> ' . self::editorLink($file, $line) . '</p>'; |
||
574 | } |
||
575 | |||
576 | // styles and dump |
||
577 | return $this->renderStyles() . '<div class="nette-inner tracy-inner nette-Doctrine2Panel">' . $e . $s . '</div>'; |
||
578 | } |
||
579 | |||
580 | |||
581 | |||
582 | /** |
||
583 | * Returns syntax highlighted SQL command. |
||
584 | * This method is same as Nette\Database\Helpers::dumpSql except for parameters handling. |
||
585 | * @link https://github.com/nette/database/blob/667143b2d5b940f78c8dc9212f95b1bbc033c6a3/src/Database/Helpers.php#L75-L138 |
||
586 | * @author David Grudl |
||
587 | * @param string $sql |
||
588 | * @return string |
||
589 | */ |
||
590 | public static function highlightQuery($sql) |
||
591 | { |
||
592 | 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'; |
||
593 | static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE|WITH|INSTANCE\s+OF'; |
||
594 | |||
595 | // insert new lines |
||
596 | $sql = " $sql "; |
||
597 | $sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql); |
||
598 | |||
599 | // reduce spaces |
||
600 | $sql = preg_replace('#[ \t]{2,}#', ' ', $sql); |
||
601 | |||
602 | $sql = wordwrap($sql, 100); |
||
603 | $sql = preg_replace('#([ \t]*\r?\n){2,}#', "\n", $sql); |
||
604 | |||
605 | // syntax highlight |
||
606 | $sql = htmlspecialchars($sql, ENT_IGNORE, 'UTF-8'); |
||
607 | $sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function ($matches) { |
||
608 | if (!empty($matches[1])) { // comment |
||
609 | return '<em style="color:gray">' . $matches[1] . '</em>'; |
||
610 | |||
611 | } elseif (!empty($matches[2])) { // error |
||
612 | return '<strong style="color:red">' . $matches[2] . '</strong>'; |
||
613 | |||
614 | } elseif (!empty($matches[3])) { // most important keywords |
||
615 | return '<strong style="color:blue">' . $matches[3] . '</strong>'; |
||
616 | |||
617 | } elseif (!empty($matches[4])) { // other keywords |
||
618 | return '<strong style="color:green">' . $matches[4] . '</strong>'; |
||
619 | } |
||
620 | }, $sql); |
||
621 | |||
622 | return '<pre class="dump">' . trim($sql) . "</pre>\n"; |
||
623 | } |
||
624 | |||
625 | |||
626 | |||
627 | /** |
||
628 | * @param string $query |
||
629 | * @param array $params |
||
630 | * @param array $types |
||
631 | * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform |
||
632 | * @throws \Doctrine\DBAL\DBALException |
||
633 | * @throws \Nette\Utils\RegexpException |
||
634 | * @return string |
||
635 | */ |
||
636 | public static function formatQuery($query, $params, array $types = [], AbstractPlatform $platform = NULL) |
||
637 | { |
||
638 | if (!$platform) { |
||
639 | $platform = new Doctrine\DBAL\Platforms\MySqlPlatform(); |
||
640 | } |
||
641 | |||
642 | if (!$types) { |
||
643 | foreach ($params as $key => $param) { |
||
644 | if (is_array($param)) { |
||
645 | $types[$key] = Doctrine\DBAL\Connection::PARAM_STR_ARRAY; |
||
646 | |||
647 | } else { |
||
648 | $types[$key] = 'string'; |
||
649 | } |
||
650 | } |
||
651 | } |
||
652 | |||
653 | try { |
||
654 | list($query, $params, $types) = \Doctrine\DBAL\SQLParserUtils::expandListParameters($query, $params, $types); |
||
655 | } catch (Doctrine\DBAL\SQLParserUtilsException $e) { |
||
656 | } |
||
657 | |||
658 | $formattedParams = []; |
||
659 | foreach ($params as $key => $param) { |
||
660 | if (isset($types[$key])) { |
||
661 | if (is_scalar($types[$key]) && array_key_exists($types[$key], Type::getTypesMap())) { |
||
662 | $types[$key] = Type::getType($types[$key]); |
||
663 | } |
||
664 | |||
665 | /** @var Type[] $types */ |
||
666 | if ($types[$key] instanceof Type) { |
||
667 | $param = $types[$key]->convertToDatabaseValue($param, $platform); |
||
668 | } |
||
669 | } |
||
670 | |||
671 | $formattedParams[] = SimpleParameterFormatter::format($param); |
||
672 | } |
||
673 | $params = $formattedParams; |
||
674 | |||
675 | if (Nette\Utils\Validators::isList($params)) { |
||
676 | $parts = explode('?', $query); |
||
677 | if (count($params) > $parts) { |
||
678 | throw new Kdyby\Doctrine\InvalidStateException("Too mny parameters passed to query."); |
||
679 | } |
||
680 | |||
681 | return implode('', Kdyby\Doctrine\Helpers::zipper($parts, $params)); |
||
682 | } |
||
683 | |||
684 | return Strings::replace($query, '~(\\:[a-z][a-z0-9]*|\\?[0-9]*)~i', function ($m) use (&$params) { |
||
685 | if (substr($m[0], 0, 1) === '?') { |
||
686 | if (strlen($m[0]) > 1) { |
||
687 | if (isset($params[$k = substr($m[0], 1)])) { |
||
688 | return $params[$k]; |
||
689 | } |
||
690 | |||
691 | } else { |
||
692 | return array_shift($params); |
||
693 | } |
||
694 | |||
695 | } else { |
||
696 | if (isset($params[$k = substr($m[0], 1)])) { |
||
697 | return $params[$k]; |
||
698 | } |
||
699 | } |
||
700 | |||
701 | return $m[0]; |
||
702 | }); |
||
703 | } |
||
704 | |||
705 | |||
706 | |||
707 | /** |
||
708 | * @param \Doctrine\Common\Annotations\AnnotationException $e |
||
709 | * |
||
710 | * @return string |
||
711 | */ |
||
712 | public static function highlightAnnotationLine(AnnotationException $e) |
||
747 | |||
748 | |||
749 | |||
750 | /** |
||
751 | * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method $refl |
||
752 | * @param \Exception|\Throwable $e |
||
753 | * @param int $startLine |
||
754 | * |
||
755 | * @return int|string |
||
756 | */ |
||
757 | public static function calculateErrorLine(\Reflector $refl, $e, $startLine = NULL) |
||
783 | |||
784 | |||
785 | |||
786 | /** |
||
787 | * @param \Reflector|\Nette\Reflection\ClassType|\Nette\Reflection\Method $refl |
||
788 | * @param int $symbolPos |
||
789 | * |
||
790 | * @return int |
||
791 | */ |
||
792 | protected static function calculateAffectedLine(\Reflector $refl, $symbolPos) |
||
802 | |||
803 | |||
804 | |||
805 | /** |
||
806 | * @param \Reflector|Nette\Reflection\ClassType|Nette\Reflection\Method $refl |
||
807 | * @param $annotation |
||
808 | */ |
||
809 | private static function findRenamed(\Reflector $refl, $annotation) |
||
810 | { |
||
811 | $parser = new Doctrine\Common\Annotations\PhpParser(); |
||
812 | $imports = $parser->parseClass($refl instanceof \ReflectionClass ? $refl : $refl->getDeclaringClass()); |
||
813 | |||
814 | $annotationClass = ltrim($annotation, '@'); |
||
815 | foreach ($imports as $alias => $import) { |
||
816 | if (!Strings::startsWith($annotationClass, $import)) { |
||
817 | continue; |
||
818 | } |
||
819 | |||
820 | $aliased = str_replace(Strings::lower($import), $alias, Strings::lower($annotationClass)); |
||
821 | $searchFor = preg_quote(Strings::lower($aliased)); |
||
822 | |||
823 | if (!$m = Strings::match($refl->getDocComment(), "~(?P<usage>@?$searchFor)~i")) { |
||
824 | continue; |
||
825 | } |
||
826 | |||
827 | return $m['usage']; |
||
828 | } |
||
829 | |||
830 | return $annotation; |
||
831 | } |
||
832 | |||
833 | |||
834 | |||
835 | /** |
||
836 | * @param \Nette\Reflection\ClassType|\Nette\Reflection\Method|\Reflector $refl |
||
837 | * @param null $atPos |
||
838 | * |
||
839 | * @return string |
||
840 | */ |
||
841 | private static function cleanedPhpDoc(\Reflector $refl, &$atPos = NULL) |
||
845 | |||
846 | |||
847 | |||
848 | /** |
||
849 | * Returns link to editor. |
||
850 | * @author David Grudl |
||
851 | * @param string $file |
||
852 | * @param string $line |
||
853 | * @param string $text |
||
854 | * @return Nette\Utils\Html |
||
855 | */ |
||
856 | private static function editorLink($file, $line, $text = NULL) |
||
857 | { |
||
858 | if (Debugger::$editor && is_file($file) && $text !== NULL) { |
||
859 | return Nette\Utils\Html::el('a') |
||
860 | ->href(strtr(Debugger::$editor, ['%file' => rawurlencode($file), '%line' => $line])) |
||
868 | |||
869 | |||
870 | |||
871 | /****************** Registration *********************/ |
||
872 | |||
873 | |||
874 | |||
875 | public function enableLogging() |
||
891 | |||
892 | |||
893 | |||
894 | /** |
||
895 | * @param \Doctrine\DBAL\Connection $connection |
||
896 | * @return Panel |
||
897 | */ |
||
898 | public function bindConnection(Doctrine\DBAL\Connection $connection) |
||
912 | |||
913 | |||
914 | |||
915 | /** |
||
916 | * @param Doctrine\ORM\EntityManager $em |
||
917 | * @return Panel |
||
918 | */ |
||
919 | public function bindEntityManager(Doctrine\ORM\EntityManager $em) |
||
938 | |||
939 | |||
940 | |||
941 | /** |
||
942 | * Registers panel to debugger |
||
943 | * |
||
944 | * @param \Tracy\Bar $bar |
||
945 | */ |
||
946 | public function registerBarPanel(Bar $bar) |
||
950 | |||
951 | |||
952 | |||
953 | /** |
||
954 | * Registers generic exception renderer |
||
955 | */ |
||
956 | public static function registerBluescreen(Nette\DI\Container $dic) |
||
962 | |||
963 | } |
||
964 |
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 thecomposer.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
orrequire-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 you have not tested against this specific condition, such errors might go unnoticed.