khanat-opennel-code/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php

701 lines
16 KiB
PHP
Raw Normal View History

<?php
/**
* DebugKit DebugToolbar Component
*
* PHP versions 4 and 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org
* @package debug_kit
* @subpackage debug_kit.controllers.components
* @since DebugKit 0.1
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
**/
class ToolbarComponent extends Object {
/**
* Settings for the Component
*
* - forceEnable - Force the toolbar to display even if debug == 0. Default = false
* - autoRun - Automatically display the toolbar. If set to false, toolbar display can be triggered by adding
* `?debug=true` to your URL.
*
* @var array
**/
var $settings = array(
'forceEnable' => false,
'autoRun' => true
);
/**
* Controller instance reference
*
* @var object
*/
var $controller;
/**
* Components used by DebugToolbar
*
* @var array
*/
var $components = array('RequestHandler', 'Session');
/**
* The default panels the toolbar uses.
* which panels are used can be configured when attaching the component
*
* @var array
*/
var $_defaultPanels = array('history', 'session', 'request', 'sqlLog', 'timer', 'log', 'variables');
/**
* Loaded panel objects.
*
* @var array
*/
var $panels = array();
/**
* javascript files component will be using
*
* @var array
**/
var $javascript = array(
'behavior' => '/debug_kit/js/js_debug_toolbar'
);
/**
* CacheKey used for the cache file.
*
* @var string
**/
var $cacheKey = 'toolbar_cache';
/**
* Duration of the debug kit history cache
*
* @var string
**/
var $cacheDuration = '+4 hours';
/**
* initialize
*
* If debug is off the component will be disabled and not do any further time tracking
* or load the toolbar helper.
*
* @return bool
**/
function initialize(&$controller, $settings) {
$this->settings = am($this->settings, $settings);
if (!Configure::read('debug') && empty($this->settings['forceEnable'])) {
$this->enabled = false;
return false;
}
if ($this->settings['autoRun'] == false && !isset($controller->params['url']['debug'])) {
$this->enabled = false;
return false;
}
App::import('Vendor', 'DebugKit.DebugKitDebugger');
DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Component initialization', true));
DebugKitDebugger::startTimer('componentInit', __d('debug_kit', 'Component initialization and startup', true));
$panels = $this->_defaultPanels;
if (isset($settings['panels'])) {
$panels = $this->_makePanelList($settings['panels']);
unset($settings['panels']);
}
$this->cacheKey .= $this->Session->read('Config.userAgent');
if (in_array('history', $panels) || (isset($settings['history']) && $settings['history'] !== false)) {
$this->_createCacheConfig();
}
$this->_loadPanels($panels, $settings);
$this->_set($settings);
$this->controller =& $controller;
return false;
}
/**
* Go through user panels and remove default panels as indicated.
*
* @param array $userPanels The list of panels ther user has added removed.
* @return array Array of panels to use.
**/
function _makePanelList($userPanels) {
$panels = $this->_defaultPanels;
foreach ($userPanels as $key => $value) {
if (is_numeric($key)) {
$panels[] = $value;
}
if (is_string($key) && $value === false) {
$index = array_search($key, $panels);
if ($index !== false) {
unset($panels[$index]);
}
}
}
return $panels;
}
/**
* Component Startup
*
* @return bool
**/
function startup(&$controller) {
$currentViewClass = $controller->view;
$this->_makeViewClass($currentViewClass);
$controller->view = 'DebugKit.Debug';
$isHtml = (
!isset($controller->params['url']['ext']) ||
(isset($controller->params['url']['ext']) && $controller->params['url']['ext'] == 'html')
);
if (!$this->RequestHandler->isAjax() && $isHtml) {
$format = 'Html';
} else {
$format = 'FirePhp';
}
$controller->helpers['DebugKit.Toolbar'] = array(
'output' => sprintf('DebugKit.%sToolbar', $format),
'cacheKey' => $this->cacheKey,
'cacheConfig' => 'debug_kit',
'forceEnable' => $this->settings['forceEnable'],
);
$panels = array_keys($this->panels);
foreach ($panels as $panelName) {
$this->panels[$panelName]->startup($controller);
}
DebugKitDebugger::stopTimer('componentInit');
DebugKitDebugger::startTimer('controllerAction', __d('debug_kit', 'Controller action', true));
DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller action start', true));
}
/**
* beforeRedirect callback
*
* @return void
**/
function beforeRedirect(&$controller) {
if (!class_exists('DebugKitDebugger')) {
return null;
}
DebugKitDebugger::stopTimer('controllerAction');
$vars = $this->_gatherVars($controller);
$this->_saveState($controller, $vars);
}
/**
* beforeRender callback
*
* Calls beforeRender on all the panels and set the aggregate to the controller.
*
* @return void
**/
function beforeRender(&$controller) {
if (!class_exists('DebugKitDebugger')) {
return null;
}
DebugKitDebugger::stopTimer('controllerAction');
$vars = $this->_gatherVars($controller);
$this->_saveState($controller, $vars);
$controller->set(array('debugToolbarPanels' => $vars, 'debugToolbarJavascript' => $this->javascript));
DebugKitDebugger::startTimer('controllerRender', __d('debug_kit', 'Render Controller Action', true));
DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller render start', true));
}
/**
* Load a toolbar state from cache
*
* @param int $key
* @return array
**/
function loadState($key) {
$history = Cache::read($this->cacheKey, 'debug_kit');
if (isset($history[$key])) {
return $history[$key];
}
return array();
}
/**
* Create the cache config for the history
*
* @return void
* @access protected
**/
function _createCacheConfig() {
if (Configure::read('Cache.disable') !== true) {
Cache::config('debug_kit', array(
'duration' => $this->cacheDuration,
'engine' => 'File',
'path' => CACHE
));
Cache::config('default');
}
}
/**
* collects the panel contents
*
* @return array Array of all panel beforeRender()
* @access protected
**/
function _gatherVars(&$controller) {
$vars = array();
$panels = array_keys($this->panels);
foreach ($panels as $panelName) {
$panel =& $this->panels[$panelName];
$panelName = Inflector::underscore($panelName);
$vars[$panelName]['content'] = $panel->beforeRender($controller);
$elementName = Inflector::underscore($panelName) . '_panel';
if (isset($panel->elementName)) {
$elementName = $panel->elementName;
}
$vars[$panelName]['elementName'] = $elementName;
$vars[$panelName]['plugin'] = $panel->plugin;
$vars[$panelName]['title'] = $panel->title;
$vars[$panelName]['disableTimer'] = true;
}
return $vars;
}
/**
* Load Panels used in the debug toolbar
*
* @return void
* @access protected
**/
function _loadPanels($panels, $settings) {
foreach ($panels as $panel) {
$className = $panel . 'Panel';
if (!class_exists($className) && !App::import('Vendor', $className)) {
trigger_error(sprintf(__d('debug_kit', 'Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING);
continue;
}
list($plugin, $className) = pluginSplit($className);
$panelObj =& new $className($settings);
if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) {
list(, $panel) = pluginSplit($panel);
$this->panels[$panel] =& $panelObj;
}
}
}
/**
* Makes the DoppleGangerView class if it doesn't already exist.
* This allows DebugView to be compatible with all view classes.
*
* @param string $baseClassName
* @access protected
* @return void
*/
function _makeViewClass($baseClassName) {
if (!class_exists('DoppelGangerView')) {
$parent = strtolower($baseClassName) === 'view' ? false : true;
App::import('View', $baseClassName, $parent);
if (strpos($baseClassName, '.') !== false) {
list($plugin, $baseClassName) = explode('.', $baseClassName);
}
if (strpos($baseClassName, 'View') === false) {
$baseClassName .= 'View';
}
$class = "class DoppelGangerView extends $baseClassName {}";
$this->_eval($class);
}
}
/**
* Method wrapper for eval() for testing uses.
*
* @return void
**/
function _eval($code) {
eval($code);
}
/**
* Save the current state of the toolbar varibles to the cache file.
*
* @param object $controller Controller instance
* @param array $vars Vars to save.
* @access protected
* @return void
**/
function _saveState(&$controller, $vars) {
$config = Cache::config('debug_kit');
if (empty($config) || !isset($this->panels['history'])) {
return;
}
$history = Cache::read($this->cacheKey, 'debug_kit');
if (empty($history)) {
$history = array();
}
if (count($history) == $this->panels['history']->history) {
array_pop($history);
}
unset($vars['history']);
array_unshift($history, $vars);
Cache::write($this->cacheKey, $history, 'debug_kit');
}
}
/**
* Debug Panel
*
* Abstract class for debug panels.
*
* @package cake.debug_kit
*/
class DebugPanel extends Object {
/**
* Defines which plugin this panel is from so the element can be located.
*
* @var string
*/
var $plugin = null;
/**
* Defines the title for displaying on the toolbar. If null, the class name will be used.
* Overriding this allows you to define a custom name in the toolbar.
*
* @var string
*/
var $title = null;
/**
* Provide a custom element name for this panel. If null, the underscored version of the class
* name will be used.
*
* @var string
*/
var $elementName = null;
/**
* startup the panel
*
* Pull information from the controller / request
*
* @param object $controller Controller reference.
* @return void
**/
function startup(&$controller) { }
/**
* Prepare output vars before Controller Rendering.
*
* @param object $controller Controller reference.
* @return void
**/
function beforeRender(&$controller) { }
}
/**
* History Panel
*
* Provides debug information on previous requests.
*
* @package cake.debug_kit.panels
**/
class HistoryPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* Number of history elements to keep
*
* @var string
**/
var $history = 5;
/**
* Constructor
*
* @param array $settings Array of settings.
* @return void
**/
function __construct($settings) {
if (isset($settings['history'])) {
$this->history = $settings['history'];
}
}
/**
* beforeRender callback function
*
* @return array contents for panel
**/
function beforeRender(&$controller) {
$cacheKey = $controller->Toolbar->cacheKey;
$toolbarHistory = Cache::read($cacheKey, 'debug_kit');
$historyStates = array();
if (is_array($toolbarHistory) && !empty($toolbarHistory)) {
$prefix = array();
if (!empty($controller->params['prefix'])) {
$prefix[$controller->params['prefix']] = false;
}
foreach ($toolbarHistory as $i => $state) {
if (!isset($state['request']['content']['params']['url']['url'])) {
continue;
}
$historyStates[] = array(
'title' => $state['request']['content']['params']['url']['url'],
'url' => array_merge($prefix, array(
'plugin' => 'debug_kit',
'controller' => 'toolbar_access',
'action' => 'history_state',
$i + 1))
);
}
}
if (count($historyStates) >= $this->history) {
array_pop($historyStates);
}
return $historyStates;
}
}
/**
* Variables Panel
*
* Provides debug information on the View variables.
*
* @package cake.debug_kit.panels
**/
class VariablesPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* beforeRender callback
*
* @return array
**/
function beforeRender(&$controller) {
return array_merge($controller->viewVars, array('$this->data' => $controller->data));
}
}
/**
* Session Panel
*
* Provides debug information on the Session contents.
*
* @package cake.debug_kit.panels
**/
class SessionPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* beforeRender callback
*
* @param object $controller
* @access public
* @return array
*/
function beforeRender(&$controller) {
$sessions = $controller->Toolbar->Session->read();
return $sessions;
}
}
/**
* Request Panel
*
* Provides debug information on the Current request params.
*
* @package cake.debug_kit.panels
**/
class RequestPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* beforeRender callback - grabs request params
*
* @return array
**/
function beforeRender(&$controller) {
$out = array();
$out['params'] = $controller->params;
if (isset($controller->Cookie)) {
$out['cookie'] = $controller->Cookie->read();
}
$out['get'] = $_GET;
$out['currentRoute'] = Router::currentRoute();
return $out;
}
}
/**
* Timer Panel
*
* Provides debug information on all timers used in a request.
*
* @package cake.debug_kit.panels
**/
class TimerPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* startup - add in necessary helpers
*
* @return void
**/
function startup(&$controller) {
if (!in_array('Number', $controller->helpers)) {
$controller->helpers[] = 'Number';
}
if (!in_array('SimpleGraph', $controller->helpers)) {
$controller->helpers[] = 'DebugKit.SimpleGraph';
}
}
}
/**
* SqlLog Panel
*
* Provides debug information on the SQL logs and provides links to an ajax explain interface.
*
* @package cake.debug_kit.panels
**/
class SqlLogPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* Minimum number of Rows Per Millisecond that must be returned by a query before an explain
* is done.
*
* @var int
**/
var $slowRate = 20;
/**
* Gets the connection names that should have logs + dumps generated.
*
* @param string $controller
* @access public
* @return void
*/
function beforeRender(&$controller) {
if (!class_exists('ConnectionManager')) {
return array();
}
$connections = array();
$dbConfigs = ConnectionManager::sourceList();
foreach ($dbConfigs as $configName) {
$driver = null;
$db =& ConnectionManager::getDataSource($configName);
if (
(empty($db->config['driver']) && empty($db->config['datasource'])) ||
!$db->isInterfaceSupported('getLog')
) {
continue;
}
if (isset($db->config['driver'])) {
$driver = $db->config['driver'];
}
if (empty($driver) && isset($db->config['datasource'])) {
$driver = $db->config['datasource'];
}
$explain = false;
$isExplainable = ($driver === 'mysql' || $driver === 'mysqli' || $driver === 'postgres');
if ($isExplainable) {
$explain = true;
}
$connections[$configName] = $explain;
}
return array('connections' => $connections, 'threshold' => $this->slowRate);
}
}
/**
* Log Panel - Reads log entries made this request.
*
* @package cake.debug_kit.panels
*/
class LogPanel extends DebugPanel {
var $plugin = 'debug_kit';
/**
* Constructor - sets up the log listener.
*
* @return void
*/
function __construct($settings) {
parent::__construct();
if (!class_exists('CakeLog')) {
App::import('Core', 'CakeLog');
}
$existing = CakeLog::configured();
if (empty($existing)) {
CakeLog::config('default', array(
'engine' => 'FileLog'
));
}
CakeLog::config('debug_kit_log_panel', array(
'engine' => 'DebugKitLogListener',
'panel' => $this
));
}
/**
* beforeRender Callback
*
* @return array
**/
function beforeRender(&$controller) {
$logs = $this->logger->logs;
return $logs;
}
}
/**
* A CakeLog listener which saves having to munge files or other configured loggers.
*
* @package debug_kit.components
*/
class DebugKitLogListener {
var $logs = array();
/**
* Makes the reverse link needed to get the logs later.
*
* @return void
*/
function DebugKitLogListener($options) {
$options['panel']->logger =& $this;
}
/**
* Captures log messages in memory
*
* @return void
*/
function write($type, $message) {
if (!isset($this->logs[$type])) {
$this->logs[$type] = array();
}
$this->logs[$type][] = array(date('Y-m-d H:i:s'), $message);
}
}