1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12:
13:
14: if (interface_exists('Nette\Diagnostics\IBarPanel')) {
15: class_alias('Nette\Diagnostics\IBarPanel', 'IBarPanel');
16: }
17:
18:
19:
20: 21: 22: 23: 24: 25:
26: class DibiNettePanel extends DibiObject implements IBarPanel
27: {
28:
29: static public $maxLength = 1000;
30:
31:
32: public $explain;
33:
34:
35: public $filter;
36:
37:
38: private $events = array();
39:
40:
41:
42: public function __construct($explain = TRUE, $filter = NULL)
43: {
44: $this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
45: $this->explain = (bool) $explain;
46: }
47:
48:
49:
50: public function register(DibiConnection $connection)
51: {
52: if (is_callable('Nette\Diagnostics\Debugger::enable')) {
53: class_alias('Nette\Diagnostics\Debugger', 'NDebugger');
54: }
55: if (is_callable('NDebugger::enable')) {
56: NDebugger::$bar && NDebugger::$bar->addPanel($this);
57: NDebugger::$blueScreen && NDebugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
58: $connection->onEvent[] = array($this, 'logEvent');
59: } elseif (is_callable('Debugger::enable')) {
60: Debugger::$bar && Debugger::$bar->addPanel($this);
61: Debugger::$blueScreen && Debugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
62: $connection->onEvent[] = array($this, 'logEvent');
63: }
64: }
65:
66:
67:
68: 69: 70: 71:
72: public function logEvent(DibiEvent $event)
73: {
74: if (($event->type & $this->filter) === 0) {
75: return;
76: }
77: $this->events[] = $event;
78: }
79:
80:
81:
82: 83: 84: 85:
86: public function renderException($e)
87: {
88: if ($e instanceof DibiException && $e->getSql()) {
89: return array(
90: 'tab' => 'SQL',
91: 'panel' => dibi::dump($e->getSql(), TRUE),
92: );
93: }
94: }
95:
96:
97:
98: 99: 100: 101:
102: public function getTab()
103: {
104: return '<span title="dibi"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
105: . dibi::$numOfQueries . ' queries'
106: . (dibi::$totalTime ? ' / ' . sprintf('%0.1f', dibi::$totalTime * 1000) . 'ms' : '')
107: . '</span>';
108: }
109:
110:
111:
112: 113: 114: 115:
116: public function getPanel()
117: {
118: $s = NULL;
119: $h = 'htmlSpecialChars';
120: foreach ($this->events as $event) {
121: $explain = NULL;
122: if ($this->explain && $event->type === DibiEvent::SELECT) {
123: try {
124: $backup = array($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime);
125: $event->connection->onEvent = NULL;
126: $explain = dibi::dump($event->connection->nativeQuery('EXPLAIN ' . $event->sql), TRUE);
127: } catch (DibiException $e) {}
128: list($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime) = $backup;
129: }
130:
131: $s .= '<tr><td>' . sprintf('%0.3f', $event->time * 1000);
132: if ($explain) {
133: static $counter;
134: $counter++;
135: $s .= "<br /><a href='#' class='nette-toggler' rel='#nette-debug-DibiProfiler-row-$counter'>explain ►</a>";
136: }
137:
138: $s .= '</td><td class="nette-DibiProfiler-sql">' . dibi::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, TRUE);
139: if ($explain) {
140: $s .= "<div id='nette-debug-DibiProfiler-row-$counter' class='nette-collapsed'>{$explain}</div>";
141: }
142: if ($event->source) {
143: $helpers = 'Nette\Diagnostics\Helpers';
144: if (!class_exists($helpers)) {
145: $helpers = class_exists('NDebugHelpers') ? 'NDebugHelpers' : 'DebugHelpers';
146: }
147: $s .= call_user_func(array($helpers, 'editorLink'), $event->source[0], $event->source[1])->class('nette-DibiProfiler-source');
148: }
149:
150: $s .= "</td><td>{$event->count}</td><td>{$h($event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'))}</td></tr>";
151: }
152:
153: return empty($this->events) ? '' :
154: '<style> #nette-debug td.nette-DibiProfiler-sql { background: white !important }
155: #nette-debug .nette-DibiProfiler-source { color: #999 !important }
156: #nette-debug nette-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
157: <h1>Queries: ' . dibi::$numOfQueries . (dibi::$totalTime === NULL ? '' : ', time: ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms') . '</h1>
158: <div class="nette-inner nette-DibiProfiler">
159: <table>
160: <tr><th>Time ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '
161: </table>
162: </div>';
163: }
164:
165: }
166: