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