[TASK] Remove usage of deprecated CSS classes bgColorX
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Classes / Controller / ModuleController.php
1 <?php
2 namespace TYPO3\CMS\Dbal\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\BaseScriptClass;
20 use TYPO3\CMS\Backend\Template\ModuleTemplate;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Database\DatabaseConnection;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24
25 /**
26 * Script class; Backend module for DBAL extension
27 */
28 class ModuleController extends BaseScriptClass
29 {
30 /**
31 * @var string
32 */
33 protected $thisScript;
34
35 /**
36 * The name of the module
37 *
38 * @var string
39 */
40 protected $moduleName = 'tools_txdbalM1';
41
42 /**
43 * ModuleTemplateContainer
44 *
45 * @var ModuleTemplate
46 */
47 protected $moduleTemplate;
48
49 /**
50 * Initializes this module.
51 *
52 * @return void
53 */
54 public function init()
55 {
56 $this->MCONF = array(
57 'name' => $this->moduleName,
58 );
59 $this->getLanguageService()->includeLLFile('EXT:dbal/Resources/Private/Language/locallang.xlf');
60 parent::init();
61 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
62 }
63
64 /**
65 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
66 *
67 * @return void
68 */
69 public function menuConfig()
70 {
71 $languageService = $this->getLanguageService();
72 $this->MOD_MENU = array(
73 'function' => array(
74 0 => $languageService->getLL('Debug_log'),
75 'info' => $languageService->getLL('Cached_info'),
76 'sqlcheck' => $languageService->getLL('SQL_check')
77 )
78 );
79 parent::menuConfig();
80 }
81
82 /**
83 * Main function of the module. Write the content to $this->content
84 *
85 * @return void
86 */
87 public function main()
88 {
89 $languageService = $this->getLanguageService();
90 $this->thisScript = BackendUtility::getModuleUrl($this->MCONF['name']);
91 // Clean up settings:
92 $this->MOD_SETTINGS = BackendUtility::getModuleData(
93 $this->MOD_MENU,
94 GeneralUtility::_GP('SET'),
95 $this->MCONF['name']
96 );
97 // Draw the header
98 // DBAL page title:
99 $this->content .= '<h1>' . $languageService->getLL('title') . '</h1>';
100 $this->generateMenu();
101 $shortcutName = $languageService->getLL('Debug_log');
102 // Debug log:
103 switch ($this->MOD_SETTINGS['function']) {
104 case 'info':
105 $this->content .= '<h3>' . $languageService->getLL('Cached_info') . '</h3>';
106 $this->content .= '<div>' . $this->printCachedInfo() . '</div>';
107 $shortcutName = $languageService->getLL('Cached_info');
108 break;
109 case 'sqlcheck':
110 $this->content .= '<h3>' . $languageService->getLL('SQL_check') . '</h3>';
111 $this->content .= '<div>' . $this->printSqlCheck() . '</div>';
112 $shortcutName = $languageService->getLL('SQL_check');
113 break;
114 case 0:
115 $this->content .= '<h3>' . $languageService->getLL('Debug_log') . '</h3>';
116 $this->content .= '<div>' . $this->printLogMgm() . '</div>';
117 break;
118 }
119 // ShortCut
120 $shortcutButton = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->makeShortcutButton()
121 ->setModuleName($this->MCONF['name'])
122 ->setDisplayName($shortcutName)
123 ->setSetVariables(['function']);
124 $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->addButton($shortcutButton);
125 }
126
127 /**
128 * Injects the request object for the current request or subrequest
129 * As this controller goes only through the main() method, it is rather simple for now
130 *
131 * @param ServerRequestInterface $request the current request
132 * @param ResponseInterface $response
133 * @return ResponseInterface the response with the content
134 */
135 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
136 {
137 $GLOBALS['SOBE'] = $this;
138 $this->init();
139 $this->main();
140 $this->moduleTemplate->setContent($this->content);
141 $response->getBody()->write($this->moduleTemplate->renderContent());
142 return $response;
143 }
144
145 /**
146 * Displays a form to check DBAL SQL methods and parse raw SQL.
147 *
148 * @return string HTML output
149 */
150 protected function printSqlCheck()
151 {
152 $input = GeneralUtility::_GP('tx_dbal');
153 $out = '
154 <form name="sql_check" action="' . $this->thisScript . '" method="post" enctype="multipart/form-data">
155 <script type="text/javascript">
156 /*<![CDATA[*/
157 function updateQryForm(s) {
158 document.getElementById(\'tx-dbal-result\').style.display = \'none\';
159 switch(s) {
160 case \'SELECT\':
161 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
162 document.getElementById(\'tx-dbal-qryfields\').style.display = \'table-row\';
163 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
164 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
165 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
166 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
167 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
168 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
169 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
170 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
171 break;
172 case \'INSERT\':
173 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
174 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
175 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'table-row\';
176 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
177 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
178 document.getElementById(\'tx-dbal-qryinto\').style.display = \'table-row\';
179 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
180 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
181 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
182 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
183 break;
184 case \'UPDATE\':
185 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
186 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
187 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
188 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'table-row\';
189 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
190 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
191 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
192 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
193 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
194 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
195 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
196 break;
197 case \'DELETE\':
198 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
199 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
200 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
201 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
202 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
203 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
204 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
205 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
206 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
207 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
208 break;
209 }
210 }
211 /*]]>*/
212 </script>
213 <table>
214 <tr class="tableheader"><th colspan="2">Easy SQL check</th></tr>
215 <tr><td colspan="2">
216 <select name="tx_dbal[QUERY]"size="1" onchange="updateQryForm(this.options[this.selectedIndex].value)">
217 <option value="SELECT" ' . ($input['QUERY'] === 'SELECT' ? 'selected="selected"' : '') . '>SELECT</option>
218 <option value="INSERT" ' . ($input['QUERY'] === 'INSERT' ? 'selected="selected"' : '') . '>INSERT</option>
219 <option value="UPDATE" ' . ($input['QUERY'] === 'UPDATE' ? 'selected="selected"' : '') . '>UPDATE</option>
220 <option value="DELETE" ' . ($input['QUERY'] === 'DELETE' ? 'selected="selected"' : '') . '>DELETE</option>
221 </select>
222 </td></tr>
223 <tr id="tx-dbal-qryupdate" style="display:none;"><td></td><td><input name="tx_dbal[UPDATE]" value="' . $input['UPDATE'] . '" type="text" size="30" maxsize="100" /></td></tr>
224 <tr id="tx-dbal-qryfields"><td></td><td><input name="tx_dbal[FIELDS]" value="' . $input['FIELDS'] . '" type="text" size="30" maxsize="100" /></td></tr>
225 <tr id="tx-dbal-qryinsertvalues" style="display:none;"><td></td><td><textarea name="tx_dbal[INSERTVALUES]" cols="30" rows="4">' . $input['INSERTVALUES'] . '</textarea></td></tr>
226 <tr id="tx-dbal-qryupdatevalues" style="display:none;"><th>SET</th><td><textarea name="tx_dbal[UPDATEVALUES]" cols="30" rows="4">' . $input['UPDATEVALUES'] . '</textarea></td></tr>
227 <tr id="tx-dbal-qryfrom"><th>FROM</th><td><input name="tx_dbal[FROM]" value="' . $input['FROM'] . '" type="text" size="30" maxsize="100" /></td></tr>
228 <tr id="tx-dbal-qryinto" style="display:none;"><th>INTO</th><td><input name="tx_dbal[INTO]" value="' . $input['INTO'] . '" type="text" size="30" maxsize="100" /></td></tr>
229 <tr id="tx-dbal-qrywhere"><th>WHERE</th><td><input name="tx_dbal[WHERE]" value="' . $input['WHERE'] . '" type="text" size="30" maxsize="100" /></td></tr>
230 <tr id="tx-dbal-qrygroup"><th>GROUP BY</th><td><input name="tx_dbal[GROUP]" value="' . $input['GROUP'] . '" type="text" size="30" maxsize="100" /></td></tr>
231 <tr id="tx-dbal-qryorder"><th>ORDER BY</th><td><input name="tx_dbal[ORDER]" value="' . $input['ORDER'] . '" type="text" size="30" maxsize="100" /></td></tr>
232 <tr id="tx-dbal-qrylimit"><th>LIMIT</th><td><input name="tx_dbal[LIMIT]" value="' . $input['LIMIT'] . '" type="text" size="30" maxsize="100" /></td></tr>
233 <tr>
234 <td></td>
235 <td style="text-align:right;">
236 <input class="btn btn-default" type="submit" value="CHECK" />
237 </td>
238 </tr>
239 <script type="text/javascript">
240 /*<![CDATA[*/
241 updateQryForm(\'' . $input['QUERY'] . '\');
242 /*]]>*/
243 </script>
244 ';
245 $out .= '<tr id="tx-dbal-result"><th>Result:</th><td>';
246 switch ($input['QUERY']) {
247 case 'SELECT':
248 $qry = $this->getDatabaseConnection()->SELECTquery($input['FIELDS'], $input['FROM'], $input['WHERE'], $input['GROUP'], $input['ORDER'], $input['LIMIT']);
249 break;
250 case 'INSERT':
251 $qry = $this->getDatabaseConnection()->INSERTquery($input['INTO'], $this->createFieldsValuesArray($input['INSERTVALUES']));
252 break;
253 case 'UPDATE':
254 $qry = $GLOBALS['TYPO3_DB']->UPDATEquery($input['UPDATE'], $input['WHERE'], $this->createFieldsValuesArray($input['UPDATEVALUES']));
255 break;
256 case 'DELETE':
257 $qry = $GLOBALS['TYPO3_DB']->DELETEquery($input['FROM'], $input['WHERE']);
258 break;
259 }
260 $out .= '<pre>' . htmlspecialchars($qry) . '</pre></td></tr>';
261 $out .= '
262 <tr class="tableheader">
263 <th colspan="2">RAW SQL check</th>
264 </tr>
265 <tr>
266 <td colspan="2" style="text-align:right;">
267 <textarea name="tx_dbal[RAWSQL]" cols="60" rows="5">' . $input['RAWSQL'] . '</textarea>
268 <br />
269 <input class="btn btn-default" type="submit" value="CHECK" />
270 </td>
271 </tr>';
272 if (!empty($input['RAWSQL'])) {
273 $out .= '<tr>';
274 $parseResult = $GLOBALS['TYPO3_DB']->SQLparser->parseSQL($input['RAWSQL']);
275 if (is_array($parseResult)) {
276 $newQuery = $GLOBALS['TYPO3_DB']->SQLparser->compileSQL($parseResult);
277 $testResult = $GLOBALS['TYPO3_DB']->SQLparser->debug_parseSQLpartCompare($input['RAWSQL'], $newQuery);
278 if (!is_array($testResult)) {
279 $out .= '<td colspan="2">' . $newQuery;
280 } else {
281 $out .= '<td colspan="2">' . htmlspecialchars($testResult[0]) . '</td></tr>
282 <tr><th>Error:</th><td style="border:2px solid #f00;">Input query did not match the parsed and recompiled query exactly (not observing whitespace):<br />' . htmlspecialchars($testResult[1]);
283 }
284 } else {
285 $out .= '<th>Result:</th><td style="border:2px solid #f00;">' . $parseResult;
286 }
287 $out .= '</td></tr>';
288 }
289 $out .= '</table></form>';
290 return $out;
291 }
292
293 /**
294 * Parses a very simple text format into an array.
295 *
296 * Each line is seen as a key/value pair that is exploded at =. This is used
297 * in the simple SQL check to input values for INSERT and UPDATE statements.
298 *
299 * @param string $in String to parse into key/value array.
300 * @return array Array created from the input string.
301 */
302 protected function createFieldsValuesArray($in)
303 {
304 $ret = array();
305 $in = explode(LF, $in);
306 foreach ($in as $v) {
307 $fv = explode('=', $v);
308 $ret[$fv[0]] = $fv[1];
309 }
310 return $ret;
311 }
312
313 /**
314 * Prints out the cached information about the database.
315 *
316 * The DBAL caches a lot of information, e.g. about auto increment fields,
317 * field types and primary keys. This method formats all this into a HTML
318 * table to display in the BE.
319 *
320 * @return string
321 */
322 protected function printCachedInfo()
323 {
324 // Get cmd:
325 if ((string)GeneralUtility::_GP('cmd') === 'clear') {
326 $this->getDatabaseConnection()->clearCachedFieldInfo();
327 $GLOBALS['TYPO3_DB']->cacheFieldInfo();
328 }
329 $out = '<a name="autoincrement"></a><h2>auto_increment</h2>';
330 $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field</th></tr>';
331 ksort($GLOBALS['TYPO3_DB']->cache_autoIncFields);
332 foreach ($GLOBALS['TYPO3_DB']->cache_autoIncFields as $table => $field) {
333 $out .= '<tr>';
334 $out .= '<td>' . $table . '</td>';
335 $out .= '<td>' . $field . '</td>';
336 $out .= '</tr>';
337 }
338 $out .= '</tbody></table>';
339 $out .= '<a name="primarykeys"></a><h2>Primary keys</h2>';
340 $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field(s)</th></tr>';
341 ksort($GLOBALS['TYPO3_DB']->cache_primaryKeys);
342 foreach ($GLOBALS['TYPO3_DB']->cache_primaryKeys as $table => $field) {
343 $out .= '<tr>';
344 $out .= '<td>' . $table . '</td>';
345 $out .= '<td>' . $field . '</td>';
346 $out .= '</tr>';
347 }
348 $out .= '</tbody></table>';
349 $out .= '<a name="fieldtypes"></a><h2>Field types</h2>';
350 $out .= '
351 <table border="1" cellspacing="0">
352 <tbody>
353 <tr>
354 <th colspan="5">Table</th>
355 </tr>
356 <tr>
357 <th>Field</th>
358 <th>Type</th><th>
359 <a href="#metatypes">Metatype</a></th>
360 <th>NOT NULL</th>
361 <th>Default</th></th>
362 </tr>';
363 ksort($GLOBALS['TYPO3_DB']->cache_fieldType);
364 foreach ($GLOBALS['TYPO3_DB']->cache_fieldType as $table => $fields) {
365 $out .= '<th colspan="5">' . $table . '</th>';
366 foreach ($fields as $field => $data) {
367 $out .= '<tr>';
368 $out .= '<td>' . $field . '</td>';
369 $out .= '<td>' . $data['type'] . '</td>';
370 $out .= '<td>' . $data['metaType'] . '</td>';
371 $out .= '<td>' . ($data['notnull'] ? 'NOT NULL' : '') . '</td>';
372 $out .= '<td>' . $data['default'] . '</td>';
373 $out .= '</tr>';
374 }
375 }
376 $out .= '</tbody></table>';
377 $out .= '<a name="metatypes"></a><h2>Metatype explanation</h2>';
378 $out .= '<pre>
379 C: Varchar, capped to 255 characters.
380 X: Larger varchar, capped to 4000 characters (to be compatible with Oracle).
381 XL: For Oracle, returns CLOB, otherwise the largest varchar size.
382
383 C2: Multibyte varchar
384 X2: Multibyte varchar (largest size)
385
386 B: BLOB (binary large object)
387
388 D: Date (some databases do not support this, and we return a datetime type)
389 T: Datetime or Timestamp
390 L: Integer field suitable for storing booleans (0 or 1)
391 I: Integer (mapped to I4)
392 I1: 1-byte integer
393 I2: 2-byte integer
394 I4: 4-byte integer
395 I8: 8-byte integer
396 F: Floating point number
397 N: Numeric or decimal number</pre>';
398 $menu = '<a href="' . $this->thisScript . '&amp;cmd=clear">CLEAR DATA</a><hr />';
399 $menu .= '<a href="#autoincrement">auto_increment</a> | <a href="#primarykeys">Primary keys</a> | <a href="#fieldtypes">Field types</a> | <a href="#metatypes">Metatype explanation</a><hr />';
400 return $menu . $out;
401 }
402
403 /**
404 * Printing the debug-log from the DBAL extension
405 *
406 * To enabled debugging, you will have to enabled it in the configuration!
407 *
408 * @return string HTML content
409 */
410 protected function printLogMgm()
411 {
412 // Disable debugging in any case...
413 $GLOBALS['TYPO3_DB']->debug = false;
414 // Get cmd:
415 $cmd = (string)GeneralUtility::_GP('cmd');
416 switch ($cmd) {
417 case 'flush':
418 $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog');
419 $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog_where');
420 $outStr = 'Log FLUSHED!';
421 break;
422 case 'joins':
423 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('table_join,exec_time,query,script', 'tx_dbal_debuglog', 'table_join!=\'\'', 'table_join,script,exec_time,query');
424 // Init vars in which to pick up the query result:
425 $tableIndex = array();
426 $tRows = array();
427 $tRows[] = '
428 <tr>
429 <td>Execution time</td>
430 <td>Table joins</td>
431 <td>Script</td>
432 <td>Query</td>
433 </tr>';
434 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
435 $tableArray = $GLOBALS['TYPO3_DB']->SQLparser->parseFromTables($row['table_join']);
436 // Create table name index:
437 foreach ($tableArray as $a) {
438 foreach ($tableArray as $b) {
439 if ($b['table'] != $a['table']) {
440 $tableIndex[$a['table']][$b['table']] = 1;
441 }
442 }
443 }
444 // Create output row
445 $tRows[] = '
446 <tr>
447 <td>' . htmlspecialchars($row['exec_time']) . '</td>
448 <td>' . htmlspecialchars($row['table_join']) . '</td>
449 <td>' . htmlspecialchars($row['script']) . '</td>
450 <td>' . htmlspecialchars($row['query']) . '</td>
451 </tr>';
452 }
453 // Printing direct joins:
454 $outStr .= '<h4>Direct joins:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
455 // Printing total dependencies:
456 foreach ($tableIndex as $priTable => $a) {
457 foreach ($tableIndex as $tableN => $v) {
458 foreach ($v as $tableP => $vv) {
459 if ($tableP == $priTable) {
460 $tableIndex[$priTable] = array_merge($v, $a);
461 }
462 }
463 }
464 }
465 $outStr .= '<h4>Total dependencies:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
466 // Printing data rows:
467 $outStr .= '
468 <table border="1" cellspacing="0">' . implode('', $tRows) . '
469 </table>';
470 break;
471 case 'errors':
472 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('serdata,exec_time,query,script', 'tx_dbal_debuglog', 'errorFlag>0', '', 'tstamp DESC');
473 // Init vars in which to pick up the query result:
474 $tRows = array();
475 $tRows[] = '
476 <tr>
477 <td>Execution time</td>
478 <td>Error data</td>
479 <td>Script</td>
480 <td>Query</td>
481 </tr>';
482 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
483 // Create output row
484 $tRows[] = '
485 <tr>
486 <td>' . htmlspecialchars($row['exec_time']) . '</td>
487 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
488 <td>' . htmlspecialchars($row['script']) . '</td>
489 <td>' . htmlspecialchars($row['query']) . '</td>
490 </tr>';
491 }
492 // Printing data rows:
493 $outStr .= '
494 <table border="1" cellspacing="0">' . implode('', $tRows) . '
495 </table>';
496 break;
497 case 'parsing':
498 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('query,serdata', 'tx_dbal_debuglog', 'errorFlag&2=2');
499 $tRows = array();
500 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
501 // Create output row
502 $tRows[] = '
503 <tr>
504 <td>' . htmlspecialchars($row['query']) . '</td>
505 </tr>';
506 }
507 // Printing data rows:
508 $outStr .= '
509 <table border="1" cellspacing="0">' . implode('', $tRows) . '
510 </table>';
511 break;
512 case 'where':
513 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script,tablename,whereclause', 'tx_dbal_debuglog_where', '', '', 'tstamp DESC');
514 $tRows = array();
515 $tRows[] = '
516 <tr>
517 <td>Time</td>
518 <td>Script</td>
519 <td>Table</td>
520 <td>WHERE clause</td>
521 </tr>';
522 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
523 $tRows[] = '
524 <tr>
525 <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
526 <td>' . htmlspecialchars($row['script']) . '</td>
527 <td>' . htmlspecialchars($row['tablename']) . '</td>
528 <td>' . str_replace(array('\'\'', '""', 'IS NULL', 'IS NOT NULL'), array('<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row['whereclause'])) . '</td>
529 </tr>';
530 }
531 $outStr = '
532 <table border="1" cellspacing="0">' . implode('', $tRows) . '
533 </table>';
534 break;
535 default:
536 // Look for request to view specific script exec:
537 $specTime = GeneralUtility::_GP('specTime');
538 if ($specTime) {
539 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('exec_time,errorFlag,table_join,serdata,query', 'tx_dbal_debuglog', 'tstamp=' . (int)$specTime);
540 $tRows = array();
541 $tRows[] = '
542 <tr>
543 <td>Execution time</td>
544 <td>Error</td>
545 <td>Table joins</td>
546 <td>Data</td>
547 <td>Query</td>
548 </tr>';
549 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
550 $tRows[] = '
551 <tr>
552 <td>' . htmlspecialchars($row['exec_time']) . '</td>
553 <td>' . ($row['errorFlag'] ? 1 : 0) . '</td>
554 <td>' . htmlspecialchars($row['table_join']) . '</td>
555 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
556 <td>' . str_replace(array('\'\'', '""', 'IS NULL', 'IS NOT NULL'), array('<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row['query'])) . '</td>
557 </tr>';
558 }
559 } else {
560 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script, SUM(exec_time) as calc_sum, count(*) AS qrycount, MAX(errorFlag) as error', 'tx_dbal_debuglog', '', 'tstamp,script', 'tstamp DESC');
561 $tRows = array();
562 $tRows[] = '
563 <tr>
564 <td>Time</td>
565 <td># of queries</td>
566 <td>Error</td>
567 <td>Time (ms)</td>
568 <td>Script</td>
569 </tr>';
570 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
571 $tRows[] = '
572 <tr>
573 <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
574 <td>' . htmlspecialchars($row['qrycount']) . '</td>
575 <td>' . ($row['error'] ? '<strong style="color:#f00">ERR</strong>' : '') . '</td>
576 <td>' . htmlspecialchars($row['calc_sum']) . '</td>
577 <td><a href="' . $this->thisScript . '&amp;specTime=' . (int)$row['tstamp'] . '">' . htmlspecialchars($row['script']) . '</a></td>
578 </tr>';
579 }
580 }
581 $outStr = '
582 <table border="1" cellspacing="0">' . implode('', $tRows) . '
583 </table>';
584 }
585 $menu = '
586 <a href="' . $this->thisScript . '&amp;cmd=flush">FLUSH LOG</a> -
587 <a href="' . $this->thisScript . '&amp;cmd=joins">JOINS</a> -
588 <a href="' . $this->thisScript . '&amp;cmd=errors">ERRORS</a> -
589 <a href="' . $this->thisScript . '&amp;cmd=parsing">PARSING</a> -
590 <a href="' . $this->thisScript . '">LOG</a> -
591 <a href="' . $this->thisScript . '&amp;cmd=where">WHERE</a> -
592
593 <a href="' . htmlspecialchars(GeneralUtility::linkThisScript()) . '" target="tx_debuglog">[New window]</a>
594 <hr />
595 ';
596 return $menu . $outStr;
597 }
598
599 /**
600 * Generate the ModuleMenu
601 */
602 protected function generateMenu()
603 {
604 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
605 $menu->setIdentifier('DBALJumpMenu');
606 foreach ($this->MOD_MENU['function'] as $controller => $title) {
607 $item = $menu
608 ->makeMenuItem()
609 ->setHref(
610 BackendUtility::getModuleUrl(
611 $this->moduleName,
612 [
613 'id' => $this->id,
614 'SET' => [
615 'function' => $controller
616 ]
617 ]
618 )
619 )
620 ->setTitle($title);
621 if ($controller === $this->MOD_SETTINGS['function']) {
622 $item->setActive(true);
623 }
624 $menu->addMenuItem($item);
625 }
626 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
627 }
628
629 /**
630 * Returns the language service.
631 *
632 * @return \TYPO3\CMS\Lang\LanguageService
633 */
634 protected function getLanguageService()
635 {
636 return $GLOBALS['LANG'];
637 }
638
639 /**
640 * Returns the DatabaseConnection
641 *
642 * @return DatabaseConnection
643 */
644 protected function getDatabaseConnection()
645 {
646 return $GLOBALS['TYPO3_DB'];
647 }
648 }