PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/server/app/Plugin/DebugKit/Controller/Component/ToolbarComponent.php

https://bitbucket.org/albertoprb/fleetster-challenge
PHP | 487 lines | 303 code | 41 blank | 143 comment | 32 complexity | a0628a9e22eba532385cfb032a8f562d MD5 | raw file
  1. <?php
  2. App::uses('CakeLog', 'Log');
  3. App::uses('CakeLogInterface', 'Log');
  4. App::uses('DebugTimer', 'DebugKit.Lib');
  5. App::uses('DebugMemory', 'DebugKit.Lib');
  6. App::uses('HelperCollection', 'View');
  7. App::uses('CakeEventManager', 'Event');
  8. App::uses('CakeEventListener', 'Event');
  9. /**
  10. * DebugKit DebugToolbar Component
  11. *
  12. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  13. *
  14. * Licensed under The MIT License
  15. * Redistributions of files must retain the above copyright notice.
  16. *
  17. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  18. * @link http://cakephp.org
  19. * @package debug_kit
  20. * @subpackage debug_kit.controllers.components
  21. * @since DebugKit 0.1
  22. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  23. */
  24. class ToolbarComponent extends Component implements CakeEventListener {
  25. /**
  26. * Settings for the Component
  27. *
  28. * - forceEnable - Force the toolbar to display even if debug == 0. Default = false
  29. * - autoRun - Automatically display the toolbar. If set to false, toolbar display can be triggered by adding
  30. * `?debug=true` to your URL.
  31. *
  32. * @var array
  33. */
  34. public $settings = array(
  35. 'forceEnable' => false,
  36. 'autoRun' => true
  37. );
  38. /**
  39. * Controller instance reference
  40. *
  41. * @var object
  42. */
  43. public $controller;
  44. /**
  45. * Components used by DebugToolbar
  46. *
  47. * @var array
  48. */
  49. public $components = array('RequestHandler', 'Session');
  50. /**
  51. * The default panels the toolbar uses.
  52. * which panels are used can be configured when attaching the component
  53. *
  54. * @var array
  55. */
  56. protected $_defaultPanels = array(
  57. 'DebugKit.History',
  58. 'DebugKit.Session',
  59. 'DebugKit.Request',
  60. 'DebugKit.SqlLog',
  61. 'DebugKit.Timer',
  62. 'DebugKit.Log',
  63. 'DebugKit.Variables',
  64. 'DebugKit.Environment',
  65. 'DebugKit.Include'
  66. );
  67. /**
  68. * Loaded panel objects.
  69. *
  70. * @var array
  71. */
  72. public $panels = array();
  73. /**
  74. * javascript files component will be using
  75. *
  76. * @var array
  77. */
  78. public $javascript = array(
  79. 'jquery' => 'DebugKit.jquery',
  80. 'libs' => 'DebugKit.js_debug_toolbar'
  81. );
  82. /**
  83. * CSS files component will be using
  84. *
  85. * @var array
  86. */
  87. public $css = array('DebugKit.debug_toolbar.css');
  88. /**
  89. * CacheKey used for the cache file.
  90. *
  91. * @var string
  92. */
  93. public $cacheKey = 'toolbar_cache';
  94. /**
  95. * Duration of the debug kit history cache
  96. *
  97. * @var string
  98. */
  99. public $cacheDuration = '+4 hours';
  100. /**
  101. * Status whether component is enable or disable
  102. *
  103. * @var boolean
  104. */
  105. public $enabled = true;
  106. /**
  107. * Constructor
  108. *
  109. * If debug is off the component will be disabled and not do any further time tracking
  110. * or load the toolbar helper.
  111. *
  112. * @return bool
  113. */
  114. public function __construct(ComponentCollection $collection, $settings = array()) {
  115. $settings = array_merge((array)Configure::read('DebugKit'), $settings);
  116. $panels = $this->_defaultPanels;
  117. if (isset($settings['panels'])) {
  118. $panels = $this->_makePanelList($settings['panels']);
  119. unset($settings['panels']);
  120. }
  121. $this->controller = $collection->getController();
  122. parent::__construct($collection, array_merge($this->settings, (array)$settings));
  123. if (
  124. !Configure::read('debug') &&
  125. empty($this->settings['forceEnable'])
  126. ) {
  127. $this->enabled = false;
  128. return false;
  129. }
  130. if (
  131. $this->settings['autoRun'] == false &&
  132. !isset($this->controller->request->query['debug'])
  133. ) {
  134. $this->enabled = false;
  135. return false;
  136. }
  137. $this->controller->getEventManager()->attach($this);
  138. DebugMemory::record(__d('debug_kit', 'Component initialization'));
  139. $this->cacheKey .= $this->Session->read('Config.userAgent');
  140. if (
  141. in_array('DebugKit.History', $panels) ||
  142. (isset($settings['history']) && $settings['history'] !== false)
  143. ) {
  144. $this->_createCacheConfig();
  145. }
  146. $this->_loadPanels($panels, $settings);
  147. return false;
  148. }
  149. /**
  150. * Register all the timing handlers for core events.
  151. *
  152. * @return void
  153. */
  154. public function implementedEvents() {
  155. $before = function ($name) {
  156. return function () use ($name) {
  157. DebugTimer::start($name, __d('debug_kit', $name));
  158. };
  159. };
  160. $after = function ($name) {
  161. return function () use ($name) {
  162. DebugTimer::stop($name);
  163. };
  164. };
  165. return array(
  166. 'Controller.initialize' => array(
  167. array('priority' => 0, 'callable' => $before('Event: Controller.initialize')),
  168. array('priority' => 999, 'callable' => $after('Event: Controller.initialize'))
  169. ),
  170. 'Controller.startup' => array(
  171. array('priority' => 0, 'callable' => $before('Event: Controller.startup')),
  172. array('priority' => 999, 'callable' => $after('Event: Controller.startup'))
  173. ),
  174. 'Controller.beforeRender' => array(
  175. array('priority' => 0, 'callable' => $before('Event: Controller.beforeRender')),
  176. array('priority' => 999, 'callable' => $after('Event: Controller.beforeRender'))
  177. ),
  178. 'Controller.shutdown' => array(
  179. array('priority' => 0, 'callable' => $before('Event: Controller.shutdown')),
  180. array('priority' => 999, 'callable' => $after('Event: Controller.shutdown'))
  181. ),
  182. 'View.beforeRender' => array(
  183. array('priority' => 0, 'callable' => $before('Event: View.beforeRender')),
  184. array('priority' => 999, 'callable' => $after('Event: View.beforeRender'))
  185. ),
  186. 'View.afterRender' => array(
  187. array('priority' => 0, 'callable' => $before('Event: View.afterRender')),
  188. array('priority' => 999, 'callable' => $after('Event: View.afterRender'))
  189. ),
  190. 'View.beforeLayout' => array(
  191. array('priority' => 0, 'callable' => $before('Event: View.beforeLayout')),
  192. array('priority' => 999, 'callable' => $after('Event: View.beforeLayout'))
  193. ),
  194. 'View.afterLayout' => array(
  195. array('priority' => 0, 'callable' => $before('Event: View.afterLayout')),
  196. array('priority' => 999, 'callable' => $after('Event: View.afterLayout'))
  197. ),
  198. );
  199. }
  200. /**
  201. * Initialize callback.
  202. * If automatically disabled, tell component collection about the state.
  203. *
  204. * @return bool
  205. */
  206. public function initialize(Controller $controller) {
  207. if (!$this->enabled) {
  208. $this->_Collection->disable('Toolbar');
  209. }
  210. }
  211. /**
  212. * Go through user panels and remove default panels as indicated.
  213. *
  214. * @param array $userPanels The list of panels ther user has added removed.
  215. * @return array Array of panels to use.
  216. */
  217. protected function _makePanelList($userPanels) {
  218. $panels = $this->_defaultPanels;
  219. foreach ($userPanels as $key => $value) {
  220. if (is_numeric($key)) {
  221. $panels[] = $value;
  222. }
  223. if (is_string($key) && $value === false) {
  224. $index = array_search($key, $panels);
  225. if ($index !== false) {
  226. unset($panels[$index]);
  227. }
  228. // Compatibility for when panels were not
  229. // required to have a plugin prefix.
  230. $alternate = 'DebugKit.' . ucfirst($key);
  231. $index = array_search($alternate, $panels);
  232. if ($index !== false) {
  233. unset($panels[$index]);
  234. }
  235. }
  236. }
  237. return $panels;
  238. }
  239. /**
  240. * Component Startup
  241. *
  242. * @return bool
  243. */
  244. public function startup(Controller $controller) {
  245. $panels = array_keys($this->panels);
  246. foreach ($panels as $panelName) {
  247. $this->panels[$panelName]->startup($controller);
  248. }
  249. DebugTimer::start(
  250. 'controllerAction',
  251. __d('debug_kit', 'Controller action')
  252. );
  253. DebugMemory::record(
  254. __d('debug_kit', 'Controller action start')
  255. );
  256. }
  257. /**
  258. * beforeRedirect callback
  259. *
  260. * @return void
  261. */
  262. public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
  263. if (!class_exists('DebugTimer')) {
  264. return null;
  265. }
  266. DebugTimer::stop('controllerAction');
  267. DebugTimer::start(
  268. 'processToolbar',
  269. __d('debug_kit', 'Processing toolbar state')
  270. );
  271. $vars = $this->_gatherVars($controller);
  272. $this->_saveState($controller, $vars);
  273. DebugTimer::stop('processToolbar');
  274. }
  275. /**
  276. * beforeRender callback
  277. *
  278. * Calls beforeRender on all the panels and set the aggregate to the controller.
  279. *
  280. * @return void
  281. */
  282. public function beforeRender(Controller $controller) {
  283. if (!class_exists('DebugTimer')) {
  284. return null;
  285. }
  286. DebugTimer::stop('controllerAction');
  287. DebugTimer::start(
  288. 'processToolbar',
  289. __d('debug_kit', 'Processing toolbar data')
  290. );
  291. $vars = $this->_gatherVars($controller);
  292. $this->_saveState($controller, $vars);
  293. $this->javascript = array_unique(array_merge($this->javascript, $vars['javascript']));
  294. $this->css = array_unique(array_merge($this->css, $vars['css']));
  295. unset($vars['javascript'], $vars['css']);
  296. $controller->set(array(
  297. 'debugToolbarPanels' => $vars,
  298. 'debugToolbarJavascript' => $this->javascript,
  299. 'debugToolbarCss' => $this->css
  300. ));
  301. $isHtml = (
  302. !isset($controller->request->params['ext']) ||
  303. $controller->request->params['ext'] === 'html'
  304. );
  305. if (!$controller->request->is('ajax') && $isHtml) {
  306. $format = 'Html';
  307. } else {
  308. $format = 'FirePhp';
  309. }
  310. $controller->helpers[] = 'DebugKit.DebugTimer';
  311. $controller->helpers['DebugKit.Toolbar'] = array(
  312. 'output' => sprintf('DebugKit.%sToolbar', $format),
  313. 'cacheKey' => $this->cacheKey,
  314. 'cacheConfig' => 'debug_kit',
  315. 'forceEnable' => $this->settings['forceEnable'],
  316. );
  317. DebugTimer::stop('processToolbar');
  318. DebugMemory::record(__d('debug_kit', 'Controller render start'));
  319. }
  320. /**
  321. * Load a toolbar state from cache
  322. *
  323. * @param int $key
  324. * @return array
  325. */
  326. public function loadState($key) {
  327. $history = Cache::read($this->cacheKey, 'debug_kit');
  328. if (isset($history[$key])) {
  329. return $history[$key];
  330. }
  331. return array();
  332. }
  333. /**
  334. * Create the cache config for the history
  335. *
  336. * @return void
  337. */
  338. protected function _createCacheConfig() {
  339. if (Configure::read('Cache.disable') !== true) {
  340. $cache = array(
  341. 'duration' => $this->cacheDuration,
  342. 'engine' => 'File',
  343. 'path' => CACHE
  344. );
  345. if (isset($this->settings['cache'])) {
  346. $cache = array_merge($cache, $this->settings['cache']);
  347. }
  348. Cache::config('debug_kit', $cache);
  349. }
  350. }
  351. /**
  352. * collects the panel contents
  353. *
  354. * @return array Array of all panel beforeRender()
  355. */
  356. protected function _gatherVars(Controller $controller) {
  357. $vars = array('javascript' => array(), 'css' => array());
  358. $panels = array_keys($this->panels);
  359. foreach ($panels as $panelName) {
  360. $panel = $this->panels[$panelName];
  361. $panelName = Inflector::underscore($panelName);
  362. $vars[$panelName]['content'] = $panel->beforeRender($controller);
  363. $elementName = Inflector::underscore($panelName) . '_panel';
  364. if (isset($panel->elementName)) {
  365. $elementName = $panel->elementName;
  366. }
  367. $vars[$panelName]['elementName'] = $elementName;
  368. $vars[$panelName]['plugin'] = $panel->plugin;
  369. $vars[$panelName]['title'] = $panel->title;
  370. $vars[$panelName]['disableTimer'] = true;
  371. if (!empty($panel->javascript)) {
  372. $vars['javascript'] = array_merge($vars['javascript'], (array)$panel->javascript);
  373. }
  374. if (!empty($panel->css)) {
  375. $vars['css'] = array_merge($vars['css'], (array)$panel->css);
  376. }
  377. }
  378. return $vars;
  379. }
  380. /**
  381. * Load Panels used in the debug toolbar
  382. *
  383. * @return void
  384. */
  385. protected function _loadPanels($panels, $settings) {
  386. foreach ($panels as $panel) {
  387. $className = ucfirst($panel) . 'Panel';
  388. list($plugin, $className) = pluginSplit($className, true);
  389. App::uses($className, $plugin . 'Panel');
  390. if (!class_exists($className)) {
  391. trigger_error(__d('debug_kit', 'Could not load DebugToolbar panel %s', $panel), E_USER_WARNING);
  392. continue;
  393. }
  394. $panelObj = new $className($settings);
  395. if ($panelObj instanceof DebugPanel) {
  396. list(, $panel) = pluginSplit($panel);
  397. $this->panels[strtolower($panel)] = $panelObj;
  398. }
  399. }
  400. }
  401. /**
  402. * Save the current state of the toolbar varibles to the cache file.
  403. *
  404. * @param object $controller Controller instance
  405. * @param array $vars Vars to save.
  406. * @return void
  407. */
  408. protected function _saveState(Controller $controller, $vars) {
  409. $config = Cache::config('debug_kit');
  410. if (empty($config) || !isset($this->panels['history'])) {
  411. return;
  412. }
  413. $history = Cache::read($this->cacheKey, 'debug_kit');
  414. if (empty($history)) {
  415. $history = array();
  416. }
  417. if (count($history) == $this->panels['history']->history) {
  418. array_pop($history);
  419. }
  420. if (isset($vars['variables']['content'])) {
  421. // Remove unserializable native objects.
  422. array_walk_recursive($vars['variables']['content'], function (&$item) {
  423. if (
  424. $item instanceof Closure ||
  425. $item instanceof PDO ||
  426. $item instanceof SimpleXmlElement
  427. ) {
  428. $item = 'Unserializable object - ' . get_class($item);
  429. } elseif ($item instanceof Exception) {
  430. $item = sprintf(
  431. 'Unserializable object - %s. Error: %s in %s, line %s',
  432. get_class($item),
  433. $item,
  434. $item->getMessage(),
  435. $item->getFile(),
  436. $item->getLine()
  437. );
  438. }
  439. return $item;
  440. });
  441. }
  442. unset($vars['history']);
  443. array_unshift($history, $vars);
  444. Cache::write($this->cacheKey, $history, 'debug_kit');
  445. }
  446. }