sfWebDebug.class.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfWebDebug creates debug information for easy debugging in the browser.
  11. *
  12. * @package symfony
  13. * @subpackage debug
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfWebDebug.class.php 16169 2009-03-11 07:56:12Z fabien $
  16. */
  17. class sfWebDebug
  18. {
  19. protected
  20. $dispatcher = null,
  21. $logger = null,
  22. $options = array(),
  23. $panels = array();
  24. /**
  25. * Constructor.
  26. *
  27. * Available options:
  28. *
  29. * * image_root_path: The image root path
  30. *
  31. * @param sfEventDispatcher $dispatcher The event dispatcher
  32. * @param sfVarLogger $logger The logger
  33. * @param array $options An array of options
  34. */
  35. public function __construct(sfEventDispatcher $dispatcher, sfVarLogger $logger, array $options = array())
  36. {
  37. $this->dispatcher = $dispatcher;
  38. $this->logger = $logger;
  39. $this->options = $options;
  40. if (!isset($this->options['image_root_path']))
  41. {
  42. $this->options['image_root_path'] = '';
  43. }
  44. $this->configure();
  45. $this->dispatcher->notify(new sfEvent($this, 'debug.web.load_panels'));
  46. }
  47. /**
  48. * Configures the web debug toolbar.
  49. */
  50. public function configure()
  51. {
  52. $this->setPanel('symfony_version', new sfWebDebugPanelSymfonyVersion($this));
  53. if (sfConfig::get('sf_debug') && sfConfig::get('sf_cache'))
  54. {
  55. $this->setPanel('cache', new sfWebDebugPanelCache($this));
  56. }
  57. if (sfConfig::get('sf_logging_enabled'))
  58. {
  59. $this->setPanel('config', new sfWebDebugPanelConfig($this));
  60. }
  61. $this->setPanel('logs', new sfWebDebugPanelLogs($this));
  62. $this->setPanel('memory', new sfWebDebugPanelMemory($this));
  63. if (sfConfig::get('sf_debug'))
  64. {
  65. $this->setPanel('time', new sfWebDebugPanelTimer($this));
  66. }
  67. }
  68. /**
  69. * Gets the logger.
  70. *
  71. * @return sfVarLogger The logger instance
  72. */
  73. public function getLogger()
  74. {
  75. return $this->logger;
  76. }
  77. /**
  78. * Gets the event dispatcher.
  79. *
  80. * @return sfEventDispatcher The event dispatcher
  81. */
  82. public function getEventDispatcher()
  83. {
  84. return $this->dispatcher;
  85. }
  86. /**
  87. * Gets the registered panels.
  88. *
  89. * @return array The panels
  90. */
  91. public function getPanels()
  92. {
  93. return $this->panels;
  94. }
  95. /**
  96. * Sets a panel by name.
  97. *
  98. * @param string $name The panel name
  99. * @param sfWebDebugPanel $panel The panel
  100. */
  101. public function setPanel($name, sfWebDebugPanel $panel)
  102. {
  103. $this->panels[$name] = $panel;
  104. }
  105. /**
  106. * Removes a panel by name.
  107. *
  108. * @param string $name The panel name
  109. */
  110. public function removePanel($name)
  111. {
  112. unset($this->panels[$name]);
  113. }
  114. /**
  115. * Gets an option value by name.
  116. *
  117. * @param string $name The option name
  118. *
  119. * @return mixed The option value
  120. */
  121. public function getOption($name, $default = null)
  122. {
  123. return isset($this->options[$name]) ? $this->options[$name] : $default;
  124. }
  125. /**
  126. * Injects the web debug toolbar into a given HTML string.
  127. *
  128. * @param string $content The HTML content
  129. *
  130. * @return string The content with the web debug toolbar injected
  131. */
  132. public function injectToolbar($content)
  133. {
  134. $content = str_ireplace('</head>', '<style type="text/css">'.str_replace(array("\r", "\n"), ' ', $this->getStylesheet()).'</style></head>', $content);
  135. $debug = $this->asHtml();
  136. $count = 0;
  137. $content = str_ireplace('</body>', '<script type="text/javascript">'.$this->getJavascript().'</script>'.$debug.'</body>', $content, $count);
  138. if (!$count)
  139. {
  140. $content .= $debug;
  141. }
  142. return $content;
  143. }
  144. /**
  145. * Returns the web debug toolbar as HTML.
  146. *
  147. * @return string The web debug toolbar HTML
  148. */
  149. public function asHtml()
  150. {
  151. $titles = array();
  152. $panels = array();
  153. foreach ($this->panels as $name => $panel)
  154. {
  155. if ($title = $panel->getTitle())
  156. {
  157. if (($content = $panel->getPanelContent()) || $panel->getTitleUrl())
  158. {
  159. $id = sprintf('sfWebDebug%sDetails', $name);
  160. $titles[] = sprintf('<li><a title="%s" href="%s"%s>%s</a></li>',
  161. $panel->getPanelTitle(),
  162. $panel->getTitleUrl() ? $panel->getTitleUrl() : '#',
  163. $panel->getTitleUrl() ? '' : ' onclick="sfWebDebugShowDetailsFor(\''.$id.'\'); return false;"',
  164. $title
  165. );
  166. $panels[] = sprintf('<div id="%s" class="sfWebDebugTop" style="display: none"><h1>%s</h1>%s</div>',
  167. $id,
  168. $panel->getPanelTitle(),
  169. $content
  170. );
  171. }
  172. else
  173. {
  174. $titles[] = sprintf('<li>%s</li>', $title);
  175. }
  176. }
  177. }
  178. return '
  179. <div id="sfWebDebug">
  180. <div id="sfWebDebugBar" class="sfWebDebug'.ucfirst($this->getPriority($this->logger->getHighestPriority())).'">
  181. <a href="#" onclick="sfWebDebugToggleMenu(); return false;"><img src="'.$this->options['image_root_path'].'/sf.png" alt="Debug toolbar" /></a>
  182. <ul id="sfWebDebugDetails" class="sfWebDebugMenu">
  183. '.implode("\n", $titles).'
  184. <li class="last">
  185. <a href="#" onclick="document.getElementById(\'sfWebDebug\').style.display=\'none\'; return false;"><img src="'.$this->options['image_root_path'].'/close.png" alt="Close" /></a>
  186. </li>
  187. </ul>
  188. </div>
  189. '.implode("\n", $panels).'
  190. </div>
  191. ';
  192. }
  193. /**
  194. * Converts a priority value to a string.
  195. *
  196. * @param integer $value The priority value
  197. *
  198. * @return string The priority as a string
  199. */
  200. public function getPriority($value)
  201. {
  202. if ($value >= sfLogger::INFO)
  203. {
  204. return 'info';
  205. }
  206. else if ($value >= sfLogger::WARNING)
  207. {
  208. return 'warning';
  209. }
  210. else
  211. {
  212. return 'error';
  213. }
  214. }
  215. /**
  216. * Gets the javascript code to inject in the head tag.
  217. *
  218. * @param string The javascript code
  219. */
  220. public function getJavascript()
  221. {
  222. return <<<EOF
  223. /* <![CDATA[ */
  224. function sfWebDebugGetElementsByClassName(strClass, strTag, objContElm)
  225. {
  226. // http://muffinresearch.co.uk/archives/2006/04/29/getelementsbyclassname-deluxe-edition/
  227. strTag = strTag || "*";
  228. objContElm = objContElm || document;
  229. var objColl = (strTag == '*' && document.all) ? document.all : objContElm.getElementsByTagName(strTag);
  230. var arr = new Array();
  231. var delim = strClass.indexOf('|') != -1 ? '|' : ' ';
  232. var arrClass = strClass.split(delim);
  233. var j = objColl.length;
  234. for (var i = 0; i < j; i++) {
  235. if(objColl[i].className == undefined) continue;
  236. var arrObjClass = objColl[i].className.split(' ');
  237. if (delim == ' ' && arrClass.length > arrObjClass.length) continue;
  238. var c = 0;
  239. comparisonLoop:
  240. {
  241. var l = arrObjClass.length;
  242. for (var k = 0; k < l; k++) {
  243. var n = arrClass.length;
  244. for (var m = 0; m < n; m++) {
  245. if (arrClass[m] == arrObjClass[k]) c++;
  246. if (( delim == '|' && c == 1) || (delim == ' ' && c == arrClass.length)) {
  247. arr.push(objColl[i]);
  248. break comparisonLoop;
  249. }
  250. }
  251. }
  252. }
  253. }
  254. return arr;
  255. }
  256. function sfWebDebugToggleMenu()
  257. {
  258. var element = document.getElementById('sfWebDebugDetails');
  259. var cacheElements = sfWebDebugGetElementsByClassName('sfWebDebugCache');
  260. var mainCacheElements = sfWebDebugGetElementsByClassName('sfWebDebugActionCache');
  261. var panelElements = sfWebDebugGetElementsByClassName('sfWebDebugTop');
  262. if (element.style.display != 'none')
  263. {
  264. for (var i = 0; i < panelElements.length; ++i)
  265. {
  266. panelElements[i].style.display = 'none';
  267. }
  268. // hide all cache information
  269. for (var i = 0; i < cacheElements.length; ++i)
  270. {
  271. cacheElements[i].style.display = 'none';
  272. }
  273. for (var i = 0; i < mainCacheElements.length; ++i)
  274. {
  275. mainCacheElements[i].style.border = 'none';
  276. }
  277. }
  278. else
  279. {
  280. for (var i = 0; i < cacheElements.length; ++i)
  281. {
  282. cacheElements[i].style.display = '';
  283. }
  284. for (var i = 0; i < mainCacheElements.length; ++i)
  285. {
  286. mainCacheElements[i].style.border = '1px solid #f00';
  287. }
  288. }
  289. sfWebDebugToggle('sfWebDebugDetails');
  290. sfWebDebugToggle('sfWebDebugShowMenu');
  291. sfWebDebugToggle('sfWebDebugHideMenu');
  292. }
  293. function sfWebDebugShowDetailsFor(element)
  294. {
  295. if (typeof element == 'string')
  296. element = document.getElementById(element);
  297. var panelElements = sfWebDebugGetElementsByClassName('sfWebDebugTop');
  298. for (var i = 0; i < panelElements.length; ++i)
  299. {
  300. if (panelElements[i] != element)
  301. {
  302. panelElements[i].style.display = 'none';
  303. }
  304. }
  305. sfWebDebugToggle(element);
  306. }
  307. function sfWebDebugToggle(element)
  308. {
  309. if (typeof element == 'string')
  310. element = document.getElementById(element);
  311. if (element)
  312. element.style.display = element.style.display == 'none' ? '' : 'none';
  313. }
  314. function sfWebDebugToggleMessages(klass)
  315. {
  316. var elements = sfWebDebugGetElementsByClassName(klass);
  317. var x = elements.length;
  318. for (var i = 0; i < x; ++i)
  319. {
  320. sfWebDebugToggle(elements[i]);
  321. }
  322. }
  323. function sfWebDebugToggleAllLogLines(show, klass)
  324. {
  325. var elements = sfWebDebugGetElementsByClassName(klass);
  326. var x = elements.length;
  327. for (var i = 0; i < x; ++i)
  328. {
  329. elements[i].style.display = show ? '' : 'none';
  330. }
  331. }
  332. function sfWebDebugShowOnlyLogLines(type)
  333. {
  334. var types = new Array();
  335. types[0] = 'info';
  336. types[1] = 'warning';
  337. types[2] = 'error';
  338. for (klass in types)
  339. {
  340. var elements = sfWebDebugGetElementsByClassName('sfWebDebug' + types[klass].substring(0, 1).toUpperCase() + types[klass].substring(1, types[klass].length));
  341. var x = elements.length;
  342. for (var i = 0; i < x; ++i)
  343. {
  344. if ('tr' == elements[i].tagName.toLowerCase())
  345. {
  346. elements[i].style.display = (type == types[klass]) ? '' : 'none';
  347. }
  348. }
  349. }
  350. }
  351. /* ]]> */
  352. EOF;
  353. }
  354. /**
  355. * Gets the stylesheet code to inject in the head tag.
  356. *
  357. * @param string The stylesheet code
  358. */
  359. public function getStylesheet()
  360. {
  361. return <<<EOF
  362. #sfWebDebug
  363. {
  364. padding: 0;
  365. margin: 0;
  366. font-family: Arial, sans-serif;
  367. font-size: 12px;
  368. color: #333;
  369. text-align: left;
  370. line-height: 12px;
  371. }
  372. #sfWebDebug a, #sfWebDebug a:hover
  373. {
  374. text-decoration: none;
  375. border: none;
  376. background-color: transparent;
  377. color: #000;
  378. }
  379. #sfWebDebug img
  380. {
  381. border: 0;
  382. display: inline;
  383. }
  384. #sfWebDebugBar
  385. {
  386. position: absolute;
  387. margin: 0;
  388. padding: 1px 0;
  389. right: 0px;
  390. top: 0px;
  391. opacity: 0.80;
  392. filter: alpha(opacity:80);
  393. z-index: 10000;
  394. white-space: nowrap;
  395. }
  396. #sfWebDebugBar[id]
  397. {
  398. position: fixed;
  399. }
  400. #sfWebDebugBar img
  401. {
  402. vertical-align: middle;
  403. }
  404. #sfWebDebugBar .sfWebDebugMenu
  405. {
  406. padding: 5px;
  407. padding-left: 0;
  408. display: inline;
  409. margin: 0;
  410. }
  411. #sfWebDebugBar .sfWebDebugMenu li
  412. {
  413. display: inline;
  414. list-style: none;
  415. margin: 0;
  416. padding: 0 6px;
  417. }
  418. #sfWebDebugBar .sfWebDebugMenu li.last
  419. {
  420. margin: 0;
  421. padding: 0;
  422. border: 0;
  423. }
  424. #sfWebDebugDatabaseDetails li
  425. {
  426. margin: 0;
  427. margin-left: 30px;
  428. padding: 5px 0;
  429. }
  430. #sfWebDebugShortMessages li
  431. {
  432. margin-bottom: 10px;
  433. padding: 5px;
  434. background-color: #ddd;
  435. }
  436. #sfWebDebugShortMessages li
  437. {
  438. list-style: none;
  439. }
  440. #sfWebDebugDetails
  441. {
  442. margin-right: 7px;
  443. }
  444. #sfWebDebug pre
  445. {
  446. line-height: 1.3;
  447. margin-bottom: 10px;
  448. }
  449. #sfWebDebug h1
  450. {
  451. font-size: 16px;
  452. font-weight: bold;
  453. margin-bottom: 20px;
  454. padding: 0;
  455. border: 0px;
  456. background-color: #eee;
  457. }
  458. #sfWebDebug h2
  459. {
  460. font-size: 14px;
  461. font-weight: bold;
  462. margin: 10px 0;
  463. padding: 0;
  464. border: 0px;
  465. background: none;
  466. }
  467. #sfWebDebug .sfWebDebugTop
  468. {
  469. position: absolute;
  470. left: 0px;
  471. top: 0px;
  472. width: 98%;
  473. padding: 0 1%;
  474. margin: 0;
  475. z-index: 9999;
  476. background-color: #efefef;
  477. border-bottom: 1px solid #aaa;
  478. }
  479. #sfWebDebugLog
  480. {
  481. margin: 0;
  482. padding: 3px;
  483. font-size: 11px;
  484. }
  485. #sfWebDebugLogMenu li
  486. {
  487. display: inline;
  488. list-style: none;
  489. margin: 0;
  490. padding: 0 5px;
  491. border-right: 1px solid #aaa;
  492. }
  493. #sfWebDebugConfigSummary
  494. {
  495. display: inline;
  496. padding: 5px;
  497. background-color: #ddd;
  498. border: 1px solid #aaa;
  499. margin: 20px 0;
  500. }
  501. #sfWebDebugConfigSummary li
  502. {
  503. list-style: none;
  504. display: inline;
  505. margin: 0;
  506. padding: 0 5px;
  507. }
  508. #sfWebDebugConfigSummary li.last
  509. {
  510. border: 0;
  511. }
  512. .sfWebDebugInfo, .sfWebDebugInfo td
  513. {
  514. background-color: #ddd;
  515. }
  516. .sfWebDebugWarning, .sfWebDebugWarning td
  517. {
  518. background-color: orange;
  519. }
  520. .sfWebDebugError, .sfWebDebugError td
  521. {
  522. background-color: #f99;
  523. }
  524. .sfWebDebugLogNumber
  525. {
  526. width: 1%;
  527. }
  528. .sfWebDebugLogType
  529. {
  530. width: 1%;
  531. white-space: nowrap;
  532. color: darkgreen;
  533. }
  534. .sfWebDebugLogInfo
  535. {
  536. color: blue;
  537. }
  538. .ison
  539. {
  540. color: #3f3;
  541. margin-right: 5px;
  542. }
  543. .isoff
  544. {
  545. color: #f33;
  546. margin-right: 5px;
  547. text-decoration: line-through;
  548. }
  549. .sfWebDebugLogs
  550. {
  551. padding: 0;
  552. margin: 0;
  553. border: 1px solid #999;
  554. font-family: Arial;
  555. font-size: 11px;
  556. }
  557. .sfWebDebugLogs tr
  558. {
  559. padding: 0;
  560. margin: 0;
  561. border: 0;
  562. }
  563. .sfWebDebugLogs td
  564. {
  565. margin: 0;
  566. border: 0;
  567. padding: 1px 3px;
  568. vertical-align: top;
  569. }
  570. .sfWebDebugLogs th
  571. {
  572. margin: 0;
  573. border: 0;
  574. padding: 3px 5px;
  575. vertical-align: top;
  576. background-color: #999;
  577. color: #eee;
  578. white-space: nowrap;
  579. }
  580. .sfWebDebugDebugInfo
  581. {
  582. margin-left: 10px;
  583. padding-left: 5px;
  584. border-left: 1px solid #aaa;
  585. }
  586. .sfWebDebugCache
  587. {
  588. padding: 0;
  589. margin: 0;
  590. font-family: Arial;
  591. position: absolute;
  592. overflow: hidden;
  593. z-index: 995;
  594. font-size: 9px;
  595. padding: 2px;
  596. filter:alpha(opacity=85);
  597. -moz-opacity:0.85;
  598. opacity: 0.85;
  599. }
  600. #sfWebDebugSymfonyVersion
  601. {
  602. margin-left: 0;
  603. padding: 1px 4px;
  604. background-color: #666;
  605. color: #fff;
  606. }
  607. EOF;
  608. }
  609. }