initial commit

This commit is contained in:
2026-06-25 13:03:45 +06:00
commit 4589f4a8d0
3229 changed files with 941958 additions and 0 deletions

16
exp/Plugin/DebugKit/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
*.diff
*.err
*.orig
*.rej
*.swo
*.swp
*.vi
*~
.DS_Store
.cache
.project
.settings
.svn
errors.err
tags
/nbproject/

View File

@@ -0,0 +1,84 @@
{
// JSHint Default Configuration File (as on JSHint website)
// See http://jshint.com/docs/ for more details
"maxerr" : 500, // {int} Maximum error before stopping
// Enforcing
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
"camelcase" : true, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"indent" : 2, // {int} Number of spaces to use for indentation
"latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"noempty" : true, // true: Prohibit use of empty blocks
"nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
"plusplus" : false, // true: Prohibit use of `++` & `--`
"quotmark" : "single", // Quotation mark consistency:
// false : do nothing (default)
// true : ensure whatever is used is consistent
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"trailing" : true, // true: Prohibit trailing whitespaces
"maxparams" : false, // {int} Max number of formal params allowed per function
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
"maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
"maxlen" : 120, // {int} Max number of characters per line
// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : false, // true: Tolerate use of `== null`
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
"funcscope" : false, // true: Tolerate defining variables inside control statements"
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
"iterator" : false, // true: Tolerate using the `__iterator__` property
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
"laxcomma" : false, // true: Tolerate comma-first style coding
"loopfunc" : false, // true: Tolerate functions being defined in loops
"multistr" : false, // true: Tolerate multi-line strings
"proto" : false, // true: Tolerate using the `__proto__` property
"scripturl" : false, // true: Tolerate script-targeted URLs
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
"validthis" : false, // true: Tolerate using this in a non-constructor function
// Environments
"browser" : true, // Web Browser (window, document, etc)
"couch" : false, // CouchDB
"devel" : true, // Development/debugging (alert, confirm, etc)
"dojo" : false, // Dojo Toolkit
"jquery" : false, // jQuery
"mootools" : false, // MooTools
"node" : false, // Node.js
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
"prototypejs" : false, // Prototype and Scriptaculous
"rhino" : false, // Rhino
"worker" : false, // Web Workers
"wsh" : false, // Windows Scripting Host
"yui" : false, // Yahoo User Interface
// Legacy
"nomen" : false, // true: Prohibit dangling `_` in variables
"onevar" : false, // true: Allow only one `var` statement per function
"passfail" : false, // true: Stop on first error
"white" : true, // true: Check against strict whitespace and indentation rules
// Custom Globals
"predef" : [ ] // additional predefined global variables
}

View File

@@ -0,0 +1,84 @@
language: php
php:
- 5.3
- 5.4
- 5.5
env:
- CAKE_VERSION=2.3.10 DB=mysql
- CAKE_VERSION=2.3.10 DB=pgsql
- CAKE_VERSION=2.4.10 DB=mysql
- CAKE_VERSION=2.4.10 DB=pgsql
- CAKE_VERSION=2.6 DB=mysql
- CAKE_VERSION=2.6 DB=pgsql
install:
- git clone git://github.com/cakephp/cakephp ../cakephp && cd ../cakephp && git checkout $CAKE_VERSION
- cp -R ../debug_kit plugins/DebugKit
- chmod -R 777 ../cakephp/app/tmp
- sh -c "composer global require 'phpunit/phpunit=3.7.33'"
- sh -c "ln -s ~/.composer/vendor/phpunit/phpunit/PHPUnit ../cakephp/vendors/PHPUnit"
before_script:
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi"
- set +H
- echo "<?php
class DATABASE_CONFIG {
private \$identities = array(
'mysql' => array(
'datasource' => 'Database/Mysql',
'host' => '0.0.0.0',
'login' => 'travis'
),
'pgsql' => array(
'datasource' => 'Database/Postgres',
'host' => '127.0.0.1',
'login' => 'postgres',
'database' => 'cakephp_test',
'schema' => array(
'default' => 'public',
'test' => 'public'
)
)
);
public \$default = array(
'persistent' => false,
'host' => '',
'login' => '',
'password' => '',
'database' => 'cakephp_test',
'prefix' => ''
);
public \$test = array(
'persistent' => false,
'host' => '',
'login' => '',
'password' => '',
'database' => 'cakephp_test',
'prefix' => ''
);
public function __construct() {
\$db = 'mysql';
if (!empty(\$_SERVER['DB'])) {
\$db = \$_SERVER['DB'];
}
foreach (array('default', 'test') as \$source) {
\$config = array_merge(\$this->{\$source}, \$this->identities[\$db]);
if (is_array(\$config['database'])) {
\$config['database'] = \$config['database'][\$source];
}
if (!empty(\$config['schema']) && is_array(\$config['schema'])) {
\$config['schema'] = \$config['schema'][\$source];
}
\$this->{\$source} = \$config;
}
}
}" > ../cakephp/app/Config/database.php
script:
- ./lib/Cake/Console/cake test DebugKit AllDebugKit --stderr
notifications:
email: false

View File

@@ -0,0 +1,159 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('String', 'Utility');
/**
* Benchmark Shell Class
*
* Provides basic benchmarking of application requests
* functionally similar to Apache AB
*
* @since DebugKit 1.0
* @todo Print/export time detail information
* @todo Export/graphing of data to .dot format for graphviz visualization
* @todo Make calculated results round to leading significant digit position of std dev.
*/
class BenchmarkShell extends Shell {
/**
* Main execution of shell
*
* @return void
*/
public function main() {
$url = $this->args[0];
$defaults = array('t' => 100, 'n' => 10);
$options = array_merge($defaults, $this->params);
$times = array();
$this->out(String::insert(__d('debug_kit', '-> Testing :url'), compact('url')));
$this->out("");
for ($i = 0; $i < $options['n']; $i++) {
if (floor($options['t'] - array_sum($times)) <= 0 || $options['n'] <= 1) {
break;
}
$start = microtime(true);
file_get_contents($url);
$stop = microtime(true);
$times[] = $stop - $start;
}
$this->_results($times);
}
/**
* Prints calculated results
*
* @param array $times Array of time values
* @return void
*/
protected function _results($times) {
$duration = array_sum($times);
$requests = count($times);
$this->out(String::insert(__d('debug_kit', 'Total Requests made: :requests'), compact('requests')));
$this->out(String::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)'), compact('duration')));
$this->out("");
$this->out(String::insert(__d('debug_kit', 'Requests/Second: :rps req/sec'), array(
'rps' => round($requests / $duration, 3)
)));
$this->out(String::insert(__d('debug_kit', 'Average request time: :average-time seconds'), array(
'average-time' => round($duration / $requests, 3)
)));
$this->out(String::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev'), array(
'std-dev' => round($this->_deviation($times, true), 3)
)));
$this->out(String::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec'), array(
'longest' => round(max($times), 3),
'shortest' => round(min($times), 3)
)));
$this->out("");
}
/**
* One-pass, numerically stable calculation of population variance.
*
* Donald E. Knuth (1998).
* The Art of Computer Programming, volume 2: Seminumerical Algorithms, 3rd edn.,
* p. 232. Boston: Addison-Wesley.
*
* @param array $times Array of values
* @param boolean $sample If true, calculates an unbiased estimate of the population
* variance from a finite sample.
* @return float Variance
*/
protected function _variance($times, $sample = true) {
$n = $mean = $M2 = 0;
foreach ($times as $time) {
$n += 1;
$delta = $time - $mean;
$mean = $mean + $delta / $n;
$M2 = $M2 + $delta * ($time - $mean);
}
if ($sample) {
$n -= 1;
}
return $M2 / $n;
}
/**
* Calculate the standard deviation.
*
* @param array $times Array of values
* @param boolean $sample
* @return float Standard deviation
*/
protected function _deviation($times, $sample = true) {
return sqrt($this->_variance($times, $sample));
}
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->description(__d('debug_kit',
'Allows you to obtain some rough benchmarking statistics' .
'about a fully qualified URL.'
))
->addArgument('url', array(
'help' => __d('debug_kit', 'The URL to request.'),
'required' => true
))
->addOption('n', array(
'default' => 10,
'help' => __d('debug_kit', 'Number of iterations to perform.')
))
->addOption('t', array(
'default' => 100,
'help' => __d('debug_kit', 'Maximum total time for all iterations, in seconds.' .
'If a single iteration takes more than the timeout, only one request will be made'
)
))
->epilog(__d('debug_kit',
'Example Use: `cake benchmark --n 10 --t 100 http://localhost/testsite`. ' .
'<info>Note:</info> this benchmark does not include browser render times.'
));
return $parser;
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.3
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Folder', 'Utility');
/**
* Whitespace shell. Helps find and trim whitespace from files.
*
* Based on jperras' shell found at http://bin.cakephp.org/view/626544881
*
* @since DebugKit 1.3
*/
class WhitespaceShell extends Shell {
/**
* Will check files for whitespace and notify you
* of any files containing leading or trailing whitespace.
*
* @return void
*/
public function main() {
$path = APP;
if (!empty($this->params['path']) && strpos($this->params['path'], '/') === 0) {
$path = $this->params['path'];
} elseif (!empty($this->params['path'])) {
$path .= $this->params['path'];
}
$folder = new Folder($path);
$r = $folder->findRecursive('.*\.php');
$this->out("Checking *.php in " . $path);
foreach ($r as $file) {
$c = file_get_contents($file);
if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c)) {
$this->out('!!!contains leading whitespaces: ' . $this->shortPath($file));
}
if (preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) {
$this->out('!!!contains trailing whitespaces: ' . $this->shortPath($file));
}
}
}
/**
* Much like main() except files are modified. Be sure to have
* backups or use version control.
*
* @return void
*/
public function trim() {
$path = APP;
if (!empty($this->params['path']) && strpos($this->params['path'], '/') === 0) {
$path = $this->params['path'];
} elseif (!empty($this->params['path'])) {
$path .= $this->params['path'];
}
$folder = new Folder($path);
$r = $folder->findRecursive('.*\.php');
$this->out("Checking *.php in " . $path);
foreach ($r as $file) {
$c = file_get_contents($file);
if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c) || preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) {
$this->out('trimming' . $this->shortPath($file));
$c = preg_replace('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', '<?php', $c);
$c = preg_replace('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', '?>', $c);
file_put_contents($file, $c);
}
}
}
/**
* get the option parser
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->addOption('path', array(
'short' => 'p',
'help' => __d('cake_console', 'Absolute path or relative to APP.')
));
}
}

View File

@@ -0,0 +1,504 @@
<?php
/**
* DebugKit DebugToolbar Component
*
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('CakeLog', 'Log');
App::uses('CakeLogInterface', 'Log');
App::uses('DebugTimer', 'DebugKit.Lib');
App::uses('DebugMemory', 'DebugKit.Lib');
App::uses('HelperCollection', 'View');
App::uses('CakeEventManager', 'Event');
App::uses('CakeEventListener', 'Event');
/**
* Class ToolbarComponent
*
* @since DebugKit 0.1
*/
class ToolbarComponent extends Component implements CakeEventListener {
/**
* 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
*/
public $settings = array(
'forceEnable' => false,
'autoRun' => true
);
/**
* Controller instance reference
*
* @var object
*/
public $controller;
/**
* Components used by DebugToolbar
*
* @var array
*/
public $components = array('RequestHandler', 'Session');
/**
* The default panels the toolbar uses.
* which panels are used can be configured when attaching the component
*
* @var array
*/
protected $_defaultPanels = array(
'DebugKit.History',
'DebugKit.Session',
'DebugKit.Request',
'DebugKit.SqlLog',
'DebugKit.Timer',
'DebugKit.Log',
'DebugKit.Variables',
'DebugKit.Environment',
'DebugKit.Include'
);
/**
* Loaded panel objects.
*
* @var array
*/
public $panels = array();
/**
* javascript files component will be using
*
* @var array
*/
public $javascript = array(
'libs' => 'DebugKit./js/js_debug_toolbar'
);
/**
* CSS files component will be using
*
* @var array
*/
public $css = array('DebugKit./css/debug_toolbar.css');
/**
* CacheKey used for the cache file.
*
* @var string
*/
public $cacheKey = 'toolbar_cache';
/**
* Duration of the debug kit history cache
*
* @var string
*/
public $cacheDuration = '+4 hours';
/**
* Status whether component is enable or disable
*
* @var boolean
*/
public $enabled = true;
/**
* Constructor
*
* If debug is off the component will be disabled and not do any further time tracking
* or load the toolbar helper.
*
* @param ComponentCollection $collection
* @param array $settings
* @return \ToolbarComponent
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
$settings = array_merge((array)Configure::read('DebugKit'), $settings);
$panels = $this->_defaultPanels;
if (isset($settings['panels'])) {
$panels = $this->_makePanelList($settings['panels']);
unset($settings['panels']);
}
$this->controller = $collection->getController();
parent::__construct($collection, array_merge($this->settings, (array)$settings));
if (
!Configure::read('debug') &&
empty($this->settings['forceEnable'])
) {
$this->enabled = false;
return false;
}
if (
$this->settings['autoRun'] === false &&
!isset($this->controller->request->query['debug'])
) {
$this->enabled = false;
return false;
}
$this->controller->getEventManager()->attach($this);
DebugMemory::record(__d('debug_kit', 'Component initialization'));
$this->cacheKey .= $this->Session->read('Config.userAgent');
if (
in_array('DebugKit.History', $panels) ||
(isset($settings['history']) && $settings['history'] !== false)
) {
$this->_createCacheConfig();
}
$this->_loadPanels($panels, $settings);
return false;
}
/**
* Register all the timing handlers for core events.
*
* @return array
*/
public function implementedEvents() {
$before = function ($name) {
return function () use ($name) {
DebugTimer::start($name, $name);
};
};
$after = function ($name) {
return function () use ($name) {
DebugTimer::stop($name);
};
};
return array(
'Controller.initialize' => array(
array('priority' => 0, 'callable' => $before('Event: Controller.initialize')),
array('priority' => 999, 'callable' => $after('Event: Controller.initialize'))
),
'Controller.startup' => array(
array('priority' => 0, 'callable' => $before('Event: Controller.startup')),
array('priority' => 999, 'callable' => $after('Event: Controller.startup'))
),
'Controller.beforeRender' => array(
array('priority' => 0, 'callable' => $before('Event: Controller.beforeRender')),
array('priority' => 999, 'callable' => $after('Event: Controller.beforeRender'))
),
'Controller.shutdown' => array(
array('priority' => 0, 'callable' => $before('Event: Controller.shutdown')),
array('priority' => 999, 'callable' => $after('Event: Controller.shutdown'))
),
'View.beforeRender' => array(
array('priority' => 0, 'callable' => $before('Event: View.beforeRender')),
array('priority' => 999, 'callable' => $after('Event: View.beforeRender'))
),
'View.afterRender' => array(
array('priority' => 0, 'callable' => $before('Event: View.afterRender')),
array('priority' => 999, 'callable' => $after('Event: View.afterRender'))
),
'View.beforeLayout' => array(
array('priority' => 0, 'callable' => $before('Event: View.beforeLayout')),
array('priority' => 999, 'callable' => $after('Event: View.beforeLayout'))
),
'View.afterLayout' => array(
array('priority' => 0, 'callable' => $before('Event: View.afterLayout')),
array('priority' => 999, 'callable' => $after('Event: View.afterLayout'))
),
);
}
/**
* Initialize callback.
* If automatically disabled, tell component collection about the state.
*
* @param Controller $controller
* @return boolean
*/
public function initialize(Controller $controller) {
if (!$this->enabled) {
$this->_Collection->disable('Toolbar');
}
}
/**
* 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.
*/
protected 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]);
}
// Compatibility for when panels were not
// required to have a plugin prefix.
$alternate = 'DebugKit.' . ucfirst($key);
$index = array_search($alternate, $panels);
if ($index !== false) {
unset($panels[$index]);
}
}
}
return $panels;
}
/**
* Component Startup
*
* @param Controller $controller
* @return boolean
*/
public function startup(Controller $controller) {
$panels = array_keys($this->panels);
foreach ($panels as $panelName) {
$this->panels[$panelName]->startup($controller);
}
DebugTimer::start(
'controllerAction',
__d('debug_kit', 'Controller action')
);
DebugMemory::record(
__d('debug_kit', 'Controller action start')
);
}
/**
* beforeRedirect callback
*
* @param Controller $controller
* @param $url
* @param null $status
* @param boolean $exit
* @return void
*/
public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
if (!class_exists('DebugTimer')) {
return null;
}
DebugTimer::stop('controllerAction');
DebugTimer::start(
'processToolbar',
__d('debug_kit', 'Processing toolbar state')
);
$vars = $this->_gatherVars($controller);
$this->_saveState($controller, $vars);
DebugTimer::stop('processToolbar');
}
/**
* beforeRender callback
*
* Calls beforeRender on all the panels and set the aggregate to the controller.
*
* @param Controller $controller
* @return void
*/
public function beforeRender(Controller $controller) {
if (!class_exists('DebugTimer')) {
return null;
}
DebugTimer::stop('controllerAction');
DebugTimer::start(
'processToolbar',
__d('debug_kit', 'Processing toolbar data')
);
$vars = $this->_gatherVars($controller);
$this->_saveState($controller, $vars);
$this->javascript = array_unique(array_merge($this->javascript, $vars['javascript']));
$this->css = array_unique(array_merge($this->css, $vars['css']));
unset($vars['javascript'], $vars['css']);
$controller->set(array(
'debugToolbarPanels' => $vars,
'debugToolbarJavascript' => $this->javascript,
'debugToolbarCss' => $this->css
));
$isHtml = (
!isset($controller->request->params['ext']) ||
$controller->request->params['ext'] === 'html'
);
if (!$controller->request->is('ajax') && $isHtml) {
$format = 'Html';
} else {
$format = 'FirePhp';
}
$controller->helpers[] = 'DebugKit.DebugTimer';
$controller->helpers['DebugKit.Toolbar'] = array(
'output' => sprintf('DebugKit.%sToolbar', $format),
'cacheKey' => $this->cacheKey,
'cacheConfig' => 'debug_kit',
'forceEnable' => $this->settings['forceEnable'],
);
DebugTimer::stop('processToolbar');
DebugMemory::record(__d('debug_kit', 'Controller render start'));
}
/**
* Load a toolbar state from cache
*
* @param integer $key
* @return array
*/
public 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
*/
protected function _createCacheConfig() {
if (Configure::read('Cache.disable') === true || Cache::config('debug_kit')) {
return;
}
$cache = array(
'duration' => $this->cacheDuration,
'engine' => 'File',
'path' => CACHE
);
if (isset($this->settings['cache'])) {
$cache = array_merge($cache, $this->settings['cache']);
}
Cache::config('debug_kit', $cache);
}
/**
* collects the panel contents
*
* @param Controller $controller
* @return array Array of all panel beforeRender()
*/
protected function _gatherVars(Controller $controller) {
$vars = array('javascript' => array(), 'css' => 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;
if (!empty($panel->javascript)) {
$vars['javascript'] = array_merge($vars['javascript'], (array)$panel->javascript);
}
if (!empty($panel->css)) {
$vars['css'] = array_merge($vars['css'], (array)$panel->css);
}
}
return $vars;
}
/**
* Load Panels used in the debug toolbar
*
* @param $panels
* @param $settings
* @return void
*/
protected function _loadPanels($panels, $settings) {
foreach ($panels as $panel) {
$className = ucfirst($panel) . 'Panel';
list($plugin, $className) = pluginSplit($className, true);
App::uses($className, $plugin . 'Panel');
if (!class_exists($className)) {
trigger_error(__d('debug_kit', 'Could not load DebugToolbar panel %s', $panel), E_USER_WARNING);
continue;
}
$panelObj = new $className($settings);
if ($panelObj instanceof DebugPanel) {
list(, $panel) = pluginSplit($panel);
$this->panels[Inflector::underscore($panel)] = $panelObj;
}
}
}
/**
* Save the current state of the toolbar varibles to the cache file.
*
* @param \Controller|object $controller Controller instance
* @param array $vars Vars to save.
* @return void
*/
protected function _saveState(Controller $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);
}
if (isset($vars['variables']['content'])) {
// Remove unserializable native objects.
array_walk_recursive($vars['variables']['content'], function (&$item) {
if (
$item instanceof Closure ||
$item instanceof PDO ||
$item instanceof SimpleXmlElement
) {
$item = 'Unserializable object - ' . get_class($item);
} elseif ($item instanceof Exception) {
$item = sprintf(
'Unserializable object - %s. Error: %s in %s, line %s',
get_class($item),
$item,
$item->getMessage(),
$item->getFile(),
$item->getLine()
);
}
return $item;
});
}
unset($vars['history']);
array_unshift($history, $vars);
Cache::write($this->cacheKey, $history, 'debug_kit');
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Controller', 'Controller');
App::uses('AppController', 'Controller');
/**
* Class DebugKitAppController
*
* @since DebugKit 0.1
*/
class DebugKitAppController extends AppController {
}

View File

@@ -0,0 +1,121 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Security', 'Utility');
App::uses('DebugKitAppController', 'DebugKit.Controller');
/**
* DebugKit ToolbarAccess Controller
*
* Allows retrieval of information from the debugKit internals.
*
* @since DebugKit 1.1
*/
class ToolbarAccessController extends DebugKitAppController {
/**
* name
*
* @var string
*/
public $name = 'ToolbarAccess';
/**
* Helpers
*
* @var array
*/
public $helpers = array(
'DebugKit.Toolbar' => array('output' => 'DebugKit.HtmlToolbar'),
'Js', 'Number', 'DebugKit.SimpleGraph'
);
/**
* Components
*
* @var array
*/
public $components = array('RequestHandler', 'DebugKit.Toolbar');
/**
* Uses
*
* @var array
*/
public $uses = array('DebugKit.ToolbarAccess');
/**
* beforeFilter callback
*
* @return void
*/
public function beforeFilter() {
parent::beforeFilter();
if (isset($this->Toolbar)) {
$this->Components->disable('Toolbar');
}
$this->helpers['DebugKit.Toolbar']['cacheKey'] = $this->Toolbar->cacheKey;
$this->helpers['DebugKit.Toolbar']['cacheConfig'] = 'debug_kit';
if (isset($this->Auth) && method_exists($this->Auth, 'mapActions')) {
$this->Auth->mapActions(array(
'read' => array('history_state', 'sql_explain')
));
}
}
/**
* Get a stored history state from the toolbar cache.
*
* @param null $key
* @return void
*/
public function history_state($key = null) {
if (Configure::read('debug') == 0) {
return $this->redirect($this->referer());
}
$oldState = $this->Toolbar->loadState($key);
$this->set('toolbarState', $oldState);
$this->set('debugKitInHistoryMode', true);
$this->viewClass = null;
$this->layout = null;
}
/**
* Run SQL explain/profiling on queries. Checks the hash + the hashed queries,
* if there is mismatch a 404 will be rendered. If debug == 0 a 404 will also be
* rendered. No explain will be run if a 404 is made.
*
* @throws BadRequestException
* @return void
*/
public function sql_explain() {
if (
!$this->request->is('post') ||
empty($this->request->data['log']['sql']) ||
empty($this->request->data['log']['ds']) ||
empty($this->request->data['log']['hash']) ||
Configure::read('debug') == 0
) {
throw new BadRequestException('Invalid parameters');
}
$hash = Security::hash($this->request->data['log']['sql'] . $this->request->data['log']['ds'], 'sha1', true);
if ($hash !== $this->request->data['log']['hash']) {
throw new BadRequestException('Invalid parameters');
}
$result = $this->ToolbarAccess->explainQuery($this->request->data['log']['ds'], $this->request->data['log']['sql']);
$this->set(compact('result'));
}
}

View File

@@ -0,0 +1,28 @@
The MIT License
CakePHP(tm) : The Rapid Development PHP Framework (http://cakephp.org)
Copyright (c) 2005-2015, Cake Software Foundation, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Cake Software Foundation, Inc.
1785 E. Sahara Avenue,
Suite 490-204
Las Vegas, Nevada 89104,
United States of America.

View File

@@ -0,0 +1,227 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Debugger', 'Utility');
App::uses('FireCake', 'DebugKit.Lib');
App::uses('DebugTimer', 'DebugKit.Lib');
App::uses('DebugMemory', 'DebugKit.Lib');
/**
* DebugKit Temporary Debugger Class
*
* Provides the future features that are planned. Yet not implemented in the 1.2 code base
*
* This file will not be needed in future version of CakePHP.
*
* @since DebugKit 0.1
*/
class DebugKitDebugger extends Debugger {
/**
* destruct method
*
* Allow timer info to be displayed if the code dies or is being debugged before rendering the view
* Cheat and use the debug log class for formatting
*
* @return void
*/
public function __destruct() {
$timers = DebugTimer::getAll();
if (Configure::read('debug') < 2 || count($timers) > 0) {
return;
}
$timers = array_values($timers);
$end = end($timers);
echo '<table class="cake-sql-log"><tbody>';
echo '<caption>Debug timer info</caption>';
echo '<tr><th>Message</th><th>Start Time (ms)</th><th>End Time (ms)</th><th>Duration (ms)</th></tr>';
$i = 0;
foreach ($timers as $timer) {
$indent = 0;
for ($j = 0; $j < $i; $j++) {
if (($timers[$j]['end']) > ($timer['start']) && ($timers[$j]['end']) > ($timer['end'])) {
$indent++;
}
}
$indent = str_repeat(' &raquo; ', $indent);
extract($timer);
$start = round($start * 1000, 0);
$end = round($end * 1000, 0);
$time = round($time * 1000, 0);
echo "<tr><td>{$indent}$message</td><td>$start</td><td>$end</td><td>$time</td></tr>";
$i++;
}
echo '</tbody></table>';
}
/**
* Start an benchmarking timer.
*
* @param string $name The name of the timer to start.
* @param string $message A message for your timer
* @return boolean true
* @deprecated use DebugTimer::start()
*/
public static function startTimer($name = null, $message = null) {
return DebugTimer::start($name, $message);
}
/**
* Stop a benchmarking timer.
*
* $name should be the same as the $name used in startTimer().
*
* @param string $name The name of the timer to end.
* @return boolean true if timer was ended, false if timer was not started.
* @deprecated use DebugTimer::stop()
*/
public static function stopTimer($name = null) {
return DebugTimer::stop($name);
}
/**
* Get all timers that have been started and stopped.
* Calculates elapsed time for each timer. If clear is true, will delete existing timers
*
* @param boolean $clear false
* @return array
* @deprecated use DebugTimer::getAll()
*/
public static function getTimers($clear = false) {
return DebugTimer::getAll($clear);
}
/**
* Clear all existing timers
*
* @return boolean true
* @deprecated use DebugTimer::clear()
*/
public static function clearTimers() {
return DebugTimer::clear();
}
/**
* Get the difference in time between the timer start and timer end.
*
* @param $name string the name of the timer you want elapsed time for.
* @param $precision int the number of decimal places to return, defaults to 5.
* @return float number of seconds elapsed for timer name, 0 on missing key
* @deprecated use DebugTimer::elapsedTime()
*/
public static function elapsedTime($name = 'default', $precision = 5) {
return DebugTimer::elapsedTime($name, $precision);
}
/**
* Get the total execution time until this point
*
* @return float elapsed time in seconds since script start.
* @deprecated use DebugTimer::requestTime()
*/
public static function requestTime() {
return DebugTimer::requestTime();
}
/**
* get the time the current request started.
*
* @return float time of request start
* @deprecated use DebugTimer::requestStartTime()
*/
public static function requestStartTime() {
return DebugTimer::requestStartTime();
}
/**
* get current memory usage
*
* @return integer number of bytes ram currently in use. 0 if memory_get_usage() is not available.
* @deprecated Use DebugMemory::getCurrent() instead.
*/
public static function getMemoryUse() {
return DebugMemory::getCurrent();
}
/**
* Get peak memory use
*
* @return integer peak memory use (in bytes). Returns 0 if memory_get_peak_usage() is not available
* @deprecated Use DebugMemory::getPeak() instead.
*/
public static function getPeakMemoryUse() {
return DebugMemory::getPeak();
}
/**
* Stores a memory point in the internal tracker.
* Takes a optional message name which can be used to identify the memory point.
* If no message is supplied a debug_backtrace will be done to identifty the memory point.
* If you don't have memory_get_xx methods this will not work.
*
* @param string $message Message to identify this memory point.
* @return boolean
* @deprecated Use DebugMemory::getAll() instead.
*/
public static function setMemoryPoint($message = null) {
return DebugMemory::record($message);
}
/**
* Get all the stored memory points
*
* @param boolean $clear Whether you want to clear the memory points as well. Defaults to false.
* @return array Array of memory marks stored so far.
* @deprecated Use DebugMemory::getAll() instead.
*/
public static function getMemoryPoints($clear = false) {
return DebugMemory::getAll($clear);
}
/**
* Clear out any existing memory points
*
* @return void
* @deprecated Use DebugMemory::clear() instead.
*/
public static function clearMemoryPoints() {
DebugMemory::clear();
}
/**
* Create a FirePHP error message
*
* @param array $data Data of the error
* @param array $links Links for the error
* @return void
*/
public static function fireError($data, $links) {
$name = $data['error'] . ' - ' . $data['description'];
$message = "{$data['error']} {$data['code']} {$data['description']} on line: {$data['line']} in file: {$data['file']}";
FireCake::group($name);
FireCake::error($message, $name);
if (isset($data['context'])) {
FireCake::log($data['context'], 'Context');
}
if (isset($data['trace'])) {
FireCake::log(preg_split('/[\r\n]+/', $data['trace']), 'Trace');
}
FireCake::groupEnd();
}
}
DebugKitDebugger::getInstance('DebugKitDebugger');
Debugger::addFormat('fb', array('callback' => 'DebugKitDebugger::fireError'));

View File

@@ -0,0 +1,98 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 2.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Debugger', 'Utility');
/**
* Contains methods for Profiling memory usage.
*
*/
class DebugMemory {
/**
* An array of recorded memory use points.
*
* @var array
*/
protected static $_points = array();
/**
* Get current memory usage
*
* @return integer number of bytes ram currently in use. 0 if memory_get_usage() is not available.
*/
public static function getCurrent() {
return memory_get_usage();
}
/**
* Get peak memory use
*
* @return integer peak memory use (in bytes). Returns 0 if memory_get_peak_usage() is not available
*/
public static function getPeak() {
return memory_get_peak_usage();
}
/**
* Stores a memory point in the internal tracker.
* Takes a optional message name which can be used to identify the memory point.
* If no message is supplied a debug_backtrace will be done to identify the memory point.
*
* @param string $message Message to identify this memory point.
* @return boolean
*/
public static function record($message = null) {
$memoryUse = self::getCurrent();
if (!$message) {
$named = false;
$trace = debug_backtrace();
$message = Debugger::trimpath($trace[0]['file']) . ' line ' . $trace[0]['line'];
}
if (isset(self::$_points[$message])) {
$originalMessage = $message;
$i = 1;
while (isset(self::$_points[$message])) {
$i++;
$message = $originalMessage . ' #' . $i;
}
}
self::$_points[$message] = $memoryUse;
return true;
}
/**
* Get all the stored memory points
*
* @param boolean $clear Whether you want to clear the memory points as well. Defaults to false.
* @return array Array of memory marks stored so far.
*/
public static function getAll($clear = false) {
$marks = self::$_points;
if ($clear) {
self::$_points = array();
}
return $marks;
}
/**
* Clear out any existing memory points
*
* @return void
*/
public static function clear() {
self::$_points = array();
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Base class for debug panels.
*
* @since DebugKit 0.1
*/
class DebugPanel {
/**
* Defines which plugin this panel is from so the element can be located.
*
* @var string
*/
public $plugin = 'DebugKit';
/**
* 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
*/
public $title = null;
/**
* Panel's css files
*
* @var array
*/
public $css = array();
/**
* Panel's javascript files
*
* @var array
*/
public $javascript = array();
/**
* Provide a custom element name for this panel. If null, the underscored version of the class
* name will be used.
*
* @var string
*/
public $elementName = null;
/**
* Empty constructor
*/
public function __construct() {
}
/**
* startup the panel
*
* Pull information from the controller / request
*
* @param \Controller|object $controller Controller reference.
* @return void
*/
public function startup(Controller $controller) {
}
/**
* Prepare output vars before Controller Rendering.
*
* @param \Controller|object $controller Controller reference.
* @return void
*/
public function beforeRender(Controller $controller) {
}
}

View File

@@ -0,0 +1,201 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Debugger', 'Utility');
/**
* Contains methods for Profiling and creating timers.
*
*/
class DebugTimer {
/**
* Internal timers array
*
* @var array
*/
protected static $_timers = array();
/**
* Start an benchmarking timer.
*
* @param string $name The name of the timer to start.
* @param string $message A message for your timer
* @return boolean Always true
*/
public static function start($name = null, $message = null) {
$start = microtime(true);
if (!$name) {
$named = false;
$calledFrom = debug_backtrace();
$_name = $name = Debugger::trimpath($calledFrom[0]['file']) . ' line ' . $calledFrom[0]['line'];
} else {
$named = true;
}
if (!$message) {
$message = $name;
}
$_name = $name;
$i = 1;
while (isset(self::$_timers[$name])) {
$i++;
$name = $_name . ' #' . $i;
}
if ($i > 1) {
$message .= ' #' . $i;
}
self::$_timers[$name] = array(
'start' => $start,
'message' => $message,
'named' => $named
);
return true;
}
/**
* Stop a benchmarking timer.
*
* $name should be the same as the $name used in startTimer().
*
* @param string $name The name of the timer to end.
* @return boolean true if timer was ended, false if timer was not started.
*/
public static function stop($name = null) {
$end = microtime(true);
if (!$name) {
$names = array_reverse(array_keys(self::$_timers));
foreach ($names as $name) {
if (!empty(self::$_timers[$name]['end'])) {
continue;
}
if (empty(self::$_timers[$name]['named'])) {
break;
}
}
} else {
$i = 1;
$_name = $name;
while (isset(self::$_timers[$name])) {
if (empty(self::$_timers[$name]['end'])) {
break;
}
$i++;
$name = $_name . ' #' . $i;
}
}
if (!isset(self::$_timers[$name])) {
return false;
}
self::$_timers[$name]['end'] = $end;
return true;
}
/**
* Get all timers that have been started and stopped.
* Calculates elapsed time for each timer. If clear is true, will delete existing timers
*
* @param boolean $clear false
* @return array
*/
public static function getAll($clear = false) {
$start = self::requestStartTime();
$now = microtime(true);
$times = array();
if (!empty(self::$_timers)) {
$firstTimer = reset(self::$_timers);
$_end = $firstTimer['start'];
} else {
$_end = $now;
}
$times['Core Processing (Derived from $_SERVER["REQUEST_TIME"])'] = array(
'message' => __d('debug_kit', 'Core Processing (Derived from $_SERVER["REQUEST_TIME"])'),
'start' => 0,
'end' => $_end - $start,
'time' => round($_end - $start, 6),
'named' => null
);
foreach (self::$_timers as $name => $timer) {
if (!isset($timer['end'])) {
$timer['end'] = $now;
}
$times[$name] = array_merge($timer, array(
'start' => $timer['start'] - $start,
'end' => $timer['end'] - $start,
'time' => self::elapsedTime($name)
));
}
if ($clear) {
self::$_timers = array();
}
return $times;
}
/**
* Clear all existing timers
*
* @return boolean true
*/
public static function clear() {
self::$_timers = array();
return true;
}
/**
* Get the difference in time between the timer start and timer end.
*
* @param $name string the name of the timer you want elapsed time for.
* @param $precision int the number of decimal places to return, defaults to 5.
* @return float number of seconds elapsed for timer name, 0 on missing key
*/
public static function elapsedTime($name = 'default', $precision = 5) {
if (!isset(self::$_timers[$name]['start']) || !isset(self::$_timers[$name]['end'])) {
return 0;
}
return round(self::$_timers[$name]['end'] - self::$_timers[$name]['start'], $precision);
}
/**
* Get the total execution time until this point
*
* @return float elapsed time in seconds since script start.
*/
public static function requestTime() {
$start = self::requestStartTime();
$now = microtime(true);
return ($now - $start);
}
/**
* get the time the current request started.
*
* @return float time of request start
*/
public static function requestStartTime() {
if (defined('TIME_START')) {
$startTime = TIME_START;
} elseif (isset($GLOBALS['TIME_START'])) {
$startTime = $GLOBALS['TIME_START'];
} else {
$startTime = env('REQUEST_TIME');
}
return $startTime;
}
}

View File

@@ -0,0 +1,538 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Debugger', 'Utility');
if (!function_exists('firecake')) {
/**
* Procedural version of FireCake::log()
*
* @param $message
* @param null $label
*/
function firecake($message, $label = null) {
FireCake::fb($message, $label, 'log');
}
}
/**
* FirePHP Class for CakePHP
*
* Provides most of the functionality offered by FirePHPCore
* Interoperates with FirePHP extension for Firefox
*
* For more information see: http://www.firephp.org/
*
*/
class FireCake {
/**
* Options for FireCake.
*
* @see _defaultOptions and setOptions();
* @var string
*/
public $options = array();
/**
* Default Options used in CakeFirePhp
*
* @var string
*/
protected $_defaultOptions = array(
'maxObjectDepth' => 10,
'maxArrayDepth' => 20,
'useNativeJsonEncode' => true,
'includeLineNumbers' => true,
);
/**
* Message Levels for messages sent via FirePHP
*
* @var array
*/
protected $_levels = array(
'log' => 'LOG',
'info' => 'INFO',
'warn' => 'WARN',
'error' => 'ERROR',
'dump' => 'DUMP',
'trace' => 'TRACE',
'exception' => 'EXCEPTION',
'table' => 'TABLE',
'groupStart' => 'GROUP_START',
'groupEnd' => 'GROUP_END',
);
/**
* Version number for X-Wf-1-Plugin-1 HTML header
*
* @var string
*/
protected $_version = '0.2.1';
/**
* internal messageIndex counter
*
* @var integer
*/
protected $_messageIndex = 1;
/**
* stack of objects encoded by stringEncode()
*
* @var array
*/
protected $_encodedObjects = array();
/**
* methodIndex to include in tracebacks when using includeLineNumbers
*
* @var array
*/
protected $_methodIndex = array('info', 'log', 'warn', 'error', 'table', 'trace');
/**
* FireCake output status
*
* @var boolean
*/
protected $_enabled = true;
/**
* get Instance of the singleton
*
* @param string $class Class instance to store in the singleton. Used with subclasses and Tests.
* @return FireCake
*/
public static function getInstance($class = null) {
static $instance = array();
if (!empty($class)) {
if (!$instance || strtolower($class) !== strtolower(get_class($instance[0]))) {
$instance[0] = new $class();
$instance[0]->setOptions();
}
}
if (!isset($instance[0]) || !$instance[0]) {
$instance[0] = new FireCake();
$instance[0]->setOptions();
}
return $instance[0];
}
/**
* setOptions
*
* @param array $options Array of options to set.
* @return void
*/
public static function setOptions($options = array()) {
$_this = FireCake::getInstance();
if (empty($_this->options)) {
$_this->options = array_merge($_this->_defaultOptions, $options);
} else {
$_this->options = array_merge($_this->options, $options);
}
}
/**
* Return boolean based on presence of FirePHP extension
*
* @return boolean
*/
public static function detectClientExtension() {
$ua = FireCake::getUserAgent();
if (preg_match('/\sFirePHP\/([\.|\d]*)\s?/si', $ua, $match) && version_compare($match[1], '0.0.6', '>=')) {
return true;
}
if (env('HTTP_X_FIREPHP_VERSION') && version_compare(env('HTTP_X_FIREPHP_VERSION'), '0.6', '>=')) {
return true;
}
return false;
}
/**
* Get the Current UserAgent
*
* @return string UserAgent string of active client connection
*/
public static function getUserAgent() {
return env('HTTP_USER_AGENT');
}
/**
* Disable FireCake output
* All subsequent output calls will not be run.
*
* @return void
*/
public static function disable() {
$_this = FireCake::getInstance();
$_this->_enabled = false;
}
/**
* Enable FireCake output
*
* @return void
*/
public static function enable() {
$_this = FireCake::getInstance();
$_this->_enabled = true;
}
/**
* Convenience wrapper for LOG messages
*
* @param string $message Message to log
* @param string $label Label for message (optional)
* @return void
*/
public static function log($message, $label = null) {
FireCake::fb($message, $label, 'log');
}
/**
* Convenience wrapper for WARN messages
*
* @param string $message Message to log
* @param string $label Label for message (optional)
* @return void
*/
public static function warn($message, $label = null) {
FireCake::fb($message, $label, 'warn');
}
/**
* Convenience wrapper for INFO messages
*
* @param string $message Message to log
* @param string $label Label for message (optional)
* @return void
*/
public static function info($message, $label = null) {
FireCake::fb($message, $label, 'info');
}
/**
* Convenience wrapper for ERROR messages
*
* @param string $message Message to log
* @param string $label Label for message (optional)
* @return void
*/
public static function error($message, $label = null) {
FireCake::fb($message, $label, 'error');
}
/**
* Convenience wrapper for TABLE messages
*
* @param string $label Label for message (optional)
* @param string $message Message to log
* @return void
*/
public static function table($label, $message) {
FireCake::fb($message, $label, 'table');
}
/**
* Convenience wrapper for DUMP messages
*
* @param string $label Unique label for message
* @param string $message Message to log
* @return void
*/
public static function dump($label, $message) {
FireCake::fb($message, $label, 'dump');
}
/**
* Convenience wrapper for TRACE messages
*
* @param string $label Label for message (optional)
* @return void
*/
public static function trace($label) {
FireCake::fb($label, 'trace');
}
/**
* Convenience wrapper for GROUP messages
* Messages following the group call will be nested in a group block
*
* @param string $label Label for group (optional)
* @return void
*/
public static function group($label) {
FireCake::fb(null, $label, 'groupStart');
}
/**
* Convenience wrapper for GROUPEND messages
* Closes a group block
*
* @internal param string $label Label for group (optional)
* @return void
*/
public static function groupEnd() {
FireCake::fb(null, null, 'groupEnd');
}
/**
* fb - Send messages with FireCake to FirePHP
*
* Much like FirePHP's fb() this method can be called with various parameter counts
* fb($message) - Just send a message defaults to LOG type
* fb($message, $type) - Send a message with a specific type
* fb($message, $label, $type) - Send a message with a custom label and type.
*
* @param mixed $message Message to output. For other parameters see usage above.
* @return boolean Success
*/
public static function fb($message) {
$_this = FireCake::getInstance();
if (headers_sent($filename, $linenum)) {
trigger_error(__d('debug_kit', 'Headers already sent in %s on line %s. Cannot send log data to FirePHP.', $filename, $linenum), E_USER_WARNING);
return false;
}
if (!$_this->_enabled || !$_this->detectClientExtension()) {
return false;
}
$args = func_get_args();
$type = $label = null;
switch (count($args)) {
case 1:
$type = $_this->_levels['log'];
break;
case 2:
$type = $args[1];
break;
case 3:
$type = $args[2];
$label = $args[1];
break;
default:
trigger_error(__d('debug_kit', 'Incorrect parameter count for FireCake::fb()'), E_USER_WARNING);
return false;
}
if (isset($_this->_levels[$type])) {
$type = $_this->_levels[$type];
} else {
$type = $_this->_levels['log'];
}
$meta = array();
$skipFinalObjectEncode = false;
if ($type == $_this->_levels['trace']) {
$trace = debug_backtrace();
if (!$trace) {
return false;
}
$message = FireCake::_parseTrace($trace, $args[0]);
$skipFinalObjectEncode = true;
}
if ($_this->options['includeLineNumbers']) {
if (!isset($meta['file']) || !isset($meta['line'])) {
$trace = debug_backtrace();
for ($i = 0, $len = count($trace); $i < $len; $i++) {
$keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
$selfCall = ($keySet &&
strtolower($trace[$i]['class']) === 'firecake' &&
in_array($trace[$i]['function'], $_this->_methodIndex)
);
if ($selfCall) {
$meta['File'] = isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '';
$meta['Line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : '';
break;
}
}
}
}
$structureIndex = 1;
if ($type == $_this->_levels['dump']) {
$structureIndex = 2;
$_this->_sendHeader('X-Wf-1-Structure-2', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
} else {
$_this->_sendHeader('X-Wf-1-Structure-1', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
}
$_this->_sendHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
$_this->_sendHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/' . $_this->_version);
if ($type == $_this->_levels['groupStart']) {
$meta['Collapsed'] = 'true';
}
if ($type == $_this->_levels['dump']) {
$dump = FireCake::jsonEncode($message);
$msg = '{"' . $label . '":' . $dump . '}';
} else {
$meta['Type'] = $type;
if ($label !== null) {
$meta['Label'] = $label;
}
$msg = '[' . $_this->jsonEncode($meta) . ',' . $_this->jsonEncode($message, $skipFinalObjectEncode) . ']';
}
$lines = explode("\n", chunk_split($msg, 5000, "\n"));
foreach ($lines as $i => $line) {
if (empty($line)) {
continue;
}
$header = 'X-Wf-1-' . $structureIndex . '-1-' . $_this->_messageIndex;
if (count($lines) > 2) {
$first = ($i == 0) ? strlen($msg) : '';
$end = ($i < count($lines) - 2) ? '\\' : '';
$message = $first . '|' . $line . '|' . $end;
$_this->_sendHeader($header, $message);
} else {
$_this->_sendHeader($header, strlen($line) . '|' . $line . '|');
}
$_this->_messageIndex++;
if ($_this->_messageIndex > 99999) {
trigger_error(__d('debug_kit', 'Maximum number (99,999) of messages reached!'), E_USER_WARNING);
}
}
$_this->_sendHeader('X-Wf-1-Index', $_this->_messageIndex - 1);
return true;
}
/**
* Parse a debug backtrace
*
* @param array $trace Debug backtrace output
* @param $messageName
* @return array
*/
protected static function _parseTrace($trace, $messageName) {
$message = array();
for ($i = 0, $len = count($trace); $i < $len; $i++) {
$keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
$selfCall = ($keySet && $trace[$i]['class'] === 'FireCake');
if (!$selfCall) {
$message = array(
'Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '',
'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '',
'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '',
'Message' => $messageName,
'File' => isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '',
'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '',
'Args' => isset($trace[$i]['args']) ? FireCake::stringEncode($trace[$i]['args']) : '',
'Trace' => FireCake::_escapeTrace(array_splice($trace, $i + 1))
);
break;
}
}
return $message;
}
/**
* Fix a trace for use in output
*
* @param mixed $trace Trace to fix
* @return string
*/
protected static function _escapeTrace($trace) {
for ($i = 0, $len = count($trace); $i < $len; $i++) {
if (isset($trace[$i]['file'])) {
$trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']);
}
if (isset($trace[$i]['args'])) {
$trace[$i]['args'] = FireCake::stringEncode($trace[$i]['args']);
}
}
return $trace;
}
/**
* Encode non string objects to string.
* Filter out recursion, so no errors are raised by json_encode or $javascript->object()
*
* @param mixed $object Object or variable to encode to string.
* @param integer $objectDepth Current Depth in object chains.
* @param integer $arrayDepth Current Depth in array chains.
* @return string|Object
*/
public static function stringEncode($object, $objectDepth = 1, $arrayDepth = 1) {
$_this = FireCake::getInstance();
$return = array();
if (is_resource($object)) {
return '** ' . (string)$object . '**';
}
if (is_object($object)) {
if ($objectDepth == $_this->options['maxObjectDepth']) {
return '** Max Object Depth (' . $_this->options['maxObjectDepth'] . ') **';
}
foreach ($_this->_encodedObjects as $encoded) {
if ($encoded === $object) {
return '** Recursion (' . get_class($object) . ') **';
}
}
$_this->_encodedObjects[] = $object;
$return['__className'] = $class = get_class($object);
$properties = get_object_vars($object);
foreach ($properties as $name => $property) {
$return[$name] = FireCake::stringEncode($property, 1, $objectDepth + 1);
}
array_pop($_this->_encodedObjects);
}
if (is_array($object)) {
if ($arrayDepth == $_this->options['maxArrayDepth']) {
return '** Max Array Depth (' . $_this->options['maxArrayDepth'] . ') **';
}
foreach ($object as $key => $value) {
$return[$key] = FireCake::stringEncode($value, 1, $arrayDepth + 1);
}
}
if (is_string($object) || is_numeric($object) || is_bool($object) || $object === null) {
return $object;
}
return $return;
}
/**
* Encode an object into JSON
*
* @param mixed $object Object or array to json encode
* @param boolean $skipEncode
* @internal param bool $doIt
* @static
* @return string
*/
public static function jsonEncode($object, $skipEncode = false) {
$_this = FireCake::getInstance();
if (!$skipEncode) {
$object = FireCake::stringEncode($object);
}
return json_encode($object);
}
/**
* Send Headers - write headers.
*
* @param $name
* @param $value
* @return void
*/
protected function _sendHeader($name, $value) {
header($name . ': ' . $value);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* A CakeLog listener which saves having to munge files or other configured loggers.
*
*/
class DebugKitLog implements CakeLogInterface {
/**
* logs
*
* @var array
*/
public $logs = array();
/**
* Makes the reverse link needed to get the logs later.
*
* @param $options
* @return \DebugKitLog
*/
public function __construct($options) {
$options['panel']->logger = $this;
}
/**
* Captures log messages in memory
*
* @param $type
* @param $message
* @return void
*/
public function write($type, $message) {
if (!isset($this->logs[$type])) {
$this->logs[$type] = array();
}
$this->logs[$type][] = array(date('Y-m-d H:i:s'), (string)$message);
}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides information about your PHP and CakePHP environment to assist with debugging.
*
*/
class EnvironmentPanel extends DebugPanel {
/**
* beforeRender - Get necessary data about environment to pass back to controller
*
* @param Controller $controller
* @return array
*/
public function beforeRender(Controller $controller) {
parent::beforeRender($controller);
$return = array();
// PHP Data
$phpVer = phpversion();
$return['php'] = array_merge(array('PHP_VERSION' => $phpVer), $_SERVER);
unset($return['php']['argv']);
// CakePHP Data
$return['cake'] = array(
'APP' => APP,
'APP_DIR' => APP_DIR,
'APPLIBS' => APPLIBS,
'CACHE' => CACHE,
'CAKE' => CAKE,
'CAKE_CORE_INCLUDE_PATH' => CAKE_CORE_INCLUDE_PATH,
'CORE_PATH' => CORE_PATH,
'CAKE_VERSION' => Configure::version(),
'CSS' => CSS,
'CSS_URL' => CSS_URL,
'DS' => DS,
'FULL_BASE_URL' => FULL_BASE_URL,
'IMAGES' => IMAGES,
'IMAGES_URL' => IMAGES_URL,
'JS' => JS,
'JS_URL' => JS_URL,
'LOGS' => LOGS,
'ROOT' => ROOT,
'TESTS' => TESTS,
'TMP' => TMP,
'VENDORS' => VENDORS,
'WEBROOT_DIR' => WEBROOT_DIR,
'WWW_ROOT' => WWW_ROOT
);
$cakeConstants = array_fill_keys(
array(
'DS', 'ROOT', 'FULL_BASE_URL', 'TIME_START', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'YEAR',
'LOG_ERROR', 'FULL_BASE_URL'
), ''
);
$var = get_defined_constants(true);
$return['app'] = array_diff_key($var['user'], $return['cake'], $cakeConstants);
if (isset($var['hidef'])) {
$return['hidef'] = $var['hidef'];
}
return $return;
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on previous requests.
*
*/
class HistoryPanel extends DebugPanel {
/**
* Number of history elements to keep
*
* @var string
*/
public $history = 5;
/**
* Constructor
*
* @param array $settings Array of settings.
* @return \HistoryPanel
*/
public function __construct($settings) {
if (isset($settings['history'])) {
$this->history = $settings['history'];
}
}
/**
* beforeRender callback function
*
* @param Controller $controller
* @return array contents for panel
*/
public function beforeRender(Controller $controller) {
$cacheKey = $controller->Toolbar->cacheKey;
$toolbarHistory = Cache::read($cacheKey, 'debug_kit');
$historyStates = array();
if (is_array($toolbarHistory) && !empty($toolbarHistory)) {
$prefix = array();
if (!empty($controller->request->params['prefix'])) {
$prefix[$controller->request->params['prefix']] = false;
}
foreach ($toolbarHistory as $i => $state) {
if (!isset($state['request']['content']['url'])) {
continue;
}
$title = $state['request']['content']['url'];
$query = @$state['request']['content']['query'];
if (isset($query['url'])) {
unset($query['url']);
}
if (!empty($query)) {
$title .= '?' . urldecode(http_build_query($query));
}
$historyStates[] = array(
'title' => $title,
'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;
}
}

View File

@@ -0,0 +1,160 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides a list of included files for the current request
*
*/
class IncludePanel extends DebugPanel {
/**
* The list of plugins within the application
*
* @var <type>
*/
protected $_pluginPaths = array();
/**
* File Types
*
* @var array
*/
protected $_fileTypes = array(
'Cache', 'Config', 'Configure', 'Console', 'Component', 'Controller',
'Behavior', 'Datasource', 'Model', 'Plugin', 'Test', 'View', 'Utility',
'Network', 'Routing', 'I18n', 'Log', 'Error'
);
/**
* Get a list of plugins on construct for later use
*/
public function __construct() {
foreach (CakePlugin::loaded() as $plugin) {
$this->_pluginPaths[$plugin] = CakePlugin::path($plugin);
}
parent::__construct();
}
/**
* Get a list of files that were included and split them out into the various parts of the app
*
* @param Controller $controller
* @return array
*/
public function beforeRender(Controller $controller) {
$return = array('core' => array(), 'app' => array(), 'plugins' => array());
foreach (get_included_files() as $file) {
$pluginName = $this->_isPluginFile($file);
if ($pluginName) {
$return['plugins'][$pluginName][$this->_getFileType($file)][] = $this->_niceFileName($file, $pluginName);
} elseif ($this->_isAppFile($file)) {
$return['app'][$this->_getFileType($file)][] = $this->_niceFileName($file, 'app');
} elseif ($this->_isCoreFile($file)) {
$return['core'][$this->_getFileType($file)][] = $this->_niceFileName($file, 'core');
}
}
$return['paths'] = $this->_includePaths();
ksort($return['core']);
ksort($return['plugins']);
ksort($return['app']);
return $return;
}
/**
* Get the possible include paths
* @return array
*/
protected function _includePaths() {
$paths = array_flip(array_merge(explode(PATH_SEPARATOR, get_include_path()), array(CAKE)));
unset($paths['.']);
return array_flip($paths);
}
/**
* Check if a path is part of cake core
* @param string $file
* @return boolean
*/
protected function _isCoreFile($file) {
return strstr($file, CAKE);
}
/**
* Check if a path is from APP but not a plugin
* @param string $file
* @return boolean
*/
protected function _isAppFile($file) {
return strstr($file, APP);
}
/**
* Check if a path is from a plugin
* @param string $file
* @return boolean
*/
protected function _isPluginFile($file) {
foreach ($this->_pluginPaths as $plugin => $path) {
if (strstr($file, $path)) {
return $plugin;
}
}
return false;
}
/**
* Replace the path with APP, CORE or the plugin name
* @param string $file
* @param string
* - app for app files
* - core for core files
* - PluginName for the name of a plugin
* @return boolean
*/
protected function _niceFileName($file, $type) {
switch ($type) {
case 'app':
return str_replace(APP, 'APP/', $file);
case 'core':
return str_replace(CAKE, 'CORE/', $file);
default:
return str_replace($this->_pluginPaths[$type], $type . '/', $file);
}
}
/**
* Get the type of file (model, controller etc)
* @param string $file
* @return string
*/
protected function _getFileType($file) {
foreach ($this->_fileTypes as $type) {
if (stripos($file, '/' . $type . '/') !== false) {
return $type;
}
}
return 'Other';
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Log Panel - Reads log entries made this request.
*
*/
class LogPanel extends DebugPanel {
/**
* Constructor - sets up the log listener.
*
* @return \LogPanel
*/
public function __construct() {
parent::__construct();
$existing = CakeLog::configured();
if (empty($existing)) {
CakeLog::config('default', array(
'engine' => 'FileLog'
));
}
CakeLog::config('debug_kit_log_panel', array(
'engine' => 'DebugKit.DebugKitLog',
'panel' => $this
));
}
/**
* beforeRender Callback
*
* @param Controller $controller
* @return array
*/
public function beforeRender(Controller $controller) {
$logger = $this->logger;
return $logger;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on the Current request params.
*
*/
class RequestPanel extends DebugPanel {
/**
* beforeRender callback - grabs request params
*
* @param Controller $controller
* @return array
*/
public function beforeRender(Controller $controller) {
$out = array();
$out['params'] = $controller->request->params;
$out['url'] = $controller->request->url;
$out['query'] = $controller->request->query;
$out['data'] = $controller->request->data;
if (isset($controller->Cookie)) {
$out['cookie'] = $controller->Cookie->read();
}
$out['get'] = $_GET;
$out['currentRoute'] = Router::currentRoute();
return $out;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on the Session contents.
*
*/
class SessionPanel extends DebugPanel {
/**
* beforeRender callback
*
* @param \Controller|object $controller
* @return array
*/
public function beforeRender(Controller $controller) {
$sessions = $controller->Toolbar->Session->read();
return $sessions;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on the SQL logs and provides links to an ajax explain interface.
*
*/
class SqlLogPanel extends DebugPanel {
/**
* Minimum number of Rows Per Millisecond that must be returned by a query before an explain
* is done.
*
* @var integer
*/
public $slowRate = 20;
/**
* Gets the connection names that should have logs + dumps generated.
*
* @param \Controller|string $controller
* @return array
*/
public function beforeRender(Controller $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'])) ||
!method_exists($db, 'getLog')
) {
continue;
}
if (isset($db->config['datasource'])) {
$driver = $db->config['datasource'];
}
$explain = false;
$isExplainable = (preg_match('/(Mysql|Postgres)$/', $driver));
if ($isExplainable) {
$explain = true;
}
$connections[$configName] = $explain;
}
return array('connections' => $connections, 'threshold' => $this->slowRate);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on all timers used in a request.
*
*/
class TimerPanel extends DebugPanel {
/**
* startup - add in necessary helpers
*
* @param Controller $controller
* @return void
*/
public function startup(Controller $controller) {
if (!in_array('Number', array_keys(HelperCollection::normalizeObjectArray($controller->helpers)))) {
$controller->helpers[] = 'Number';
}
if (!in_array('SimpleGraph', array_keys(HelperCollection::normalizeObjectArray($controller->helpers)))) {
$controller->helpers[] = 'DebugKit.SimpleGraph';
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Provides debug information on the View variables.
*
*/
class VariablesPanel extends DebugPanel {
/**
* beforeRender callback
*
* @param Controller $controller
* @return array
*/
public function beforeRender(Controller $controller) {
return array_merge($controller->viewVars, array('$request->data' => $controller->request->data));
}
}

View File

@@ -0,0 +1,138 @@
# LANGUAGE translation of Debug Kit Application
# Copyright 2008 Andy Dawson <andydawson76@yahoo.co.uk>
# No version information was available in the source files.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: debug_kit-\n"
"POT-Creation-Date: 2009-05-27 09:47+0200\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Last-Translator: Andy Dawson <andydawson76@yahoo.co.uk>\n"
"Language-Team:\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Basepath: ../../../\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr ""
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr ""
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr ""
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr ""
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr ""
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr ""
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr ""
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr ""
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr ""
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr ""
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr ""
#: views/elements/log_panel.ctp:28
#: views/elements/timer_panel.ctp:54
msgid "Message"
msgstr ""
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr ""
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr ""
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr ""
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr ""
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr ""
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr ""
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr ""
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr ""
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr ""
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr ""
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr ""
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr ""
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr ""
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr ""

View File

@@ -0,0 +1,135 @@
# LANGUAGE translation of CakePHP Application
# Copyright YEAR NAME <EMAIL@ADDRESS>
# No version information was available in the source files.
#
#, fuzzy
msgid ""
msgstr "Project-Id-Version: PROJECT VERSION\n"
"POT-Creation-Date: 2009-05-27 09:47+0200\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Last-Translator: NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr ""
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr ""
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr ""
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr ""
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr ""
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr ""
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr ""
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr ""
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr ""
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr ""
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr ""
#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
msgid "Message"
msgstr ""
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr ""
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr ""
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr ""
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr ""
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr ""
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr ""
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr ""
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr ""
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr ""
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr ""
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr ""
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr ""
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr ""
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr ""

View File

@@ -0,0 +1,135 @@
# LANGUAGE translation of CakePHP Application
# Copyright YEAR NAME <EMAIL@ADDRESS>
# No version information was available in the source files.
#
#, fuzzy
msgid ""
msgstr "Project-Id-Version: PROJECT VERSION\n"
"POT-Creation-Date: 2013-06-04 12:00+0200\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Last-Translator: cake17 <gvmail76-inscription@yahoo.fr>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr "Initialisation du component et démarrage"
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr "Action du Controller"
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr "Rendu de l'Action du Controller"
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr "Ne peut charger le panel %s de DebugToolbar"
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr "Il n'y a pas de panels actifs. Vous devez activer le panel pour voir sa sortie."
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr "Historique des Requêtes"
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr "Pas de demandes antérieures enregistrées."
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr "Des requêtes antérieures sont disponibles"
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr "Restaure la requête actuelle"
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr "Logs"
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr "Date"
#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
msgid "Message"
msgstr "Message"
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr "Il n'y avait pas d'entrées de log faîtes pour cette requête"
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr "Requête"
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr "Route actuelle"
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr "Session"
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr "Logs Sql"
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr "bascule (%s) requêtes expliquées pour %s"
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr "Pas de requêtes lentes!, ou votre base de données ne supporte pas EXPLAIN"
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr "Pas de connections actives de la base de données"
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr "Mémoire"
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr "Utilisation de la Mémoire Actuelle"
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr "Utilisation de la Mémoire au niveau maximum"
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr "Timers"
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr "%s (ms)"
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr "Total du Temps de Requête"
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr "Temps en ms"
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr "Graph"
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr "Variables du View"
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr "Début en %sms de la requête, et prend %sms"

View File

@@ -0,0 +1,136 @@
# LANGUAGE translation of Debug Kit Application
# Copyright 2008 Andy Dawson <andydawson76@yahoo.co.uk>
# No version information was available in the source files.
#
msgid ""
msgstr ""
"Project-Id-Version: debug_kit-\n"
"POT-Creation-Date: 2009-05-27 09:47+0200\n"
"PO-Revision-Date: 2009-05-27 09:47+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team:none\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Basepath: ../../../\n"
"Language: lim\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr ""
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr ""
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr ""
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr ""
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr ""
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr ""
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr ""
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr ""
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr ""
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr ""
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr ""
#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
msgid "Message"
msgstr ""
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr ""
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr ""
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr ""
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr ""
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr ""
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr ""
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr ""
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr ""
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr ""
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr ""
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr ""
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr ""
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr ""
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr ""

View File

@@ -0,0 +1,141 @@
# LANGUAGE translation of Debug Kit Application
# Copyright 2008 Andy Dawson <andydawson76@yahoo.co.uk>
# No version information was available in the source files.
#
msgid ""
msgstr ""
"Project-Id-Version: debug_kit-\n"
"POT-Creation-Date: 2009-05-27 09:47+0200\n"
"PO-Revision-Date: 2014-07-17 17:04+0200\n"
"Last-Translator: Marlin Cremers <m.cremers@cvo-technologies.com>\n"
"Language-Team: \n"
"Language: nld\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 1.9\n"
"X-Poedit-Basepath: ../../../\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr "Component initializatie en opstarten"
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr "Controller Actie"
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr "Produceer Controller Actie"
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr "Kon DebugToolbar paneel %s niet laden"
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr ""
"Er zijn geen actieve panelen. Je moet een paneel aanzetten om de uitvoer te "
"zien."
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr "Aanvraag Geschiedenis"
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr "Geen vorige aanvragen gelogged."
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr "vorige aanvraag beschikbaar"
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr "Herstel naar actuele aanvraag"
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr "Logs"
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr "Tijd"
#: views/elements/log_panel.ctp:28
#: views/elements/timer_panel.ctp:54
msgid "Message"
msgstr "Bericht"
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr "Er zijn geen log vermeldingen gemaakt in deze aanvraag"
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr "Aanvraag"
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr "Huide Route"
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr "Sessie"
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr "Sql Logs"
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr "schakel (%s) aanvraag uitleg voor %s"
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr "Geen langzame vragen!, of je database ondersteund geen EXPLAIN"
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr "Geen actieve database verbindingen"
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr "Geheugen"
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr "Actueel Geheugen Gebruik"
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr "Hoogste Geheugen Gebruik"
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr "Timers"
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr "%s (ms)"
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr "Totale Aanvraag Tijd:"
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr "Tijd in ms"
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr "Diagram"
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr "View Variabelen"
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr "Starten %sms in de aanvraag, neemt %sms"

View File

@@ -0,0 +1,135 @@
# LANGUAGE translation of CakePHP Application
# Copyright YEAR NAME <EMAIL@ADDRESS>
# No version information was available in the source files.
#
#, fuzzy
msgid ""
msgstr "Project-Id-Version: PROJECT VERSION\n"
"POT-Creation-Date: 2009-05-27 09:47+0200\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Last-Translator: NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: controllers/components/toolbar.php:91
msgid "Component initialization and startup"
msgstr ""
#: controllers/components/toolbar.php:140
msgid "Controller Action"
msgstr ""
#: controllers/components/toolbar.php:167
msgid "Render Controller Action"
msgstr ""
#: controllers/components/toolbar.php:231
msgid "Could not load DebugToolbar panel %s"
msgstr ""
#: views/elements/debug_toolbar.ctp:25
msgid "There are no active panels. You must enable a panel to see its output."
msgstr ""
#: views/elements/history_panel.ctp:21
msgid "Request History"
msgstr ""
#: views/elements/history_panel.ctp:23
msgid "No previous requests logged."
msgstr ""
#: views/elements/history_panel.ctp:25
msgid "previous requests available"
msgstr ""
#: views/elements/history_panel.ctp:27
msgid "Restore to current request"
msgstr ""
#: views/elements/log_panel.ctp:21
msgid "Logs"
msgstr ""
#: views/elements/log_panel.ctp:28
msgid "Time"
msgstr ""
#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
msgid "Message"
msgstr ""
#: views/elements/log_panel.ctp:37
msgid "There were no log entries made this request"
msgstr ""
#: views/elements/request_panel.ctp:21
msgid "Request"
msgstr ""
#: views/elements/request_panel.ctp:35
msgid "Current Route"
msgstr ""
#: views/elements/session_panel.ctp:21
msgid "Session"
msgstr ""
#: views/elements/sql_log_panel.ctp:21
msgid "Sql Logs"
msgstr ""
#: views/elements/sql_log_panel.ctp:31
msgid "toggle (%s) query explains for %s"
msgstr ""
#: views/elements/sql_log_panel.ctp:39
msgid "No slow queries!, or your database does not support EXPLAIN"
msgstr ""
#: views/elements/sql_log_panel.ctp:44
msgid "No active database connections"
msgstr ""
#: views/elements/timer_panel.ctp:33
msgid "Memory"
msgstr ""
#: views/elements/timer_panel.ctp:35
msgid "Current Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:39
msgid "Peak Memory Use"
msgstr ""
#: views/elements/timer_panel.ctp:43
msgid "Timers"
msgstr ""
#: views/elements/timer_panel.ctp:45
msgid "%s (ms)"
msgstr ""
#: views/elements/timer_panel.ctp:46
msgid "Total Request Time:"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Time in ms"
msgstr ""
#: views/elements/timer_panel.ctp:54
msgid "Graph"
msgstr ""
#: views/elements/variables_panel.ctp:21
msgid "View Variables"
msgstr ""
#: views/helpers/simple_graph.php:79
msgid "Starting %sms into the request, taking %sms"
msgstr ""

View File

@@ -0,0 +1,102 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.3
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugKitDebugger', 'DebugKit.Lib');
/**
* Class TimedBehavior
*
* @since DebugKit 1.3
*/
class TimedBehavior extends ModelBehavior {
/**
* Behavior settings
*
* @var array
*/
public $settings = array();
/**
* Default setting values
*
* @var array
*/
protected $_defaults = array();
/**
* Setup the behavior and import required classes.
*
* @param \Model|object $Model Model using the behavior
* @param array $settings Settings to override for model.
* @return void
*/
public function setup(Model $Model, $settings = null) {
if (is_array($settings)) {
$this->settings[$Model->alias] = array_merge($this->_defaults, $settings);
} else {
$this->settings[$Model->alias] = $this->_defaults;
}
}
/**
* beforeFind, starts a timer for a find operation.
*
* @param Model $Model
* @param array $queryData Array of query data (not modified)
* @return boolean true
*/
public function beforeFind(Model $Model, $queryData) {
DebugKitDebugger::startTimer($Model->alias . '_find', $Model->alias . '->find()');
return true;
}
/**
* afterFind, stops a timer for a find operation.
*
* @param Model $Model
* @param array $results Array of results
* @param $primary
* @return boolean true.
*/
public function afterFind(Model $Model, $results, $primary = false) {
DebugKitDebugger::stopTimer($Model->alias . '_find');
return true;
}
/**
* beforeSave, starts a time before a save is initiated.
*
* @param Model $Model
* @param array $options
* @return boolean true
*/
public function beforeSave(Model $Model, $options = array()) {
DebugKitDebugger::startTimer($Model->alias . '_save', $Model->alias . '->save()');
return true;
}
/**
* afterSave, stop the timer started from a save.
*
* @param \Model $Model
* @param string $created
* @return boolean Always true
*/
public function afterSave(Model $Model, $created, $options = array()) {
DebugKitDebugger::stopTimer($Model->alias . '_save');
return true;
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AppModel', 'Model');
/**
* Class DebugKitAppModel
*
* @since DebugKit 0.1
*/
class DebugKitAppModel extends AppModel {
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.3
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('ConnectionManager', 'Model');
/**
* Class ToolbarAccess
*
* Contains logic for accessing DebugKit specific information.
*/
class ToolbarAccess extends Object {
/**
* Runs an explain on a query if the connection supports EXPLAIN.
* currently only PostgreSQL and MySQL are supported.
*
* @param string $connection Connection name
* @param string $query SQL query to explain / find query plan for.
* @return array Array of explain information or empty array if connection is unsupported.
*/
public function explainQuery($connection, $query) {
$db = ConnectionManager::getDataSource($connection);
$datasource = $db->config['datasource'];
$return = array();
if (preg_match('/(Mysql|Postgres)$/', $datasource)) {
$explained = $db->query('EXPLAIN ' . $query);
if (preg_match('/Postgres$/', $datasource)) {
$queryPlan = array();
foreach ($explained as $postgreValue) {
$queryPlan[] = array($postgreValue[0]['QUERY PLAN']);
}
$return = array_merge(array(array('')), $queryPlan);
} else {
$keys = array_keys($explained[0][0]);
foreach ($explained as $mysqlValue) {
$queryPlan[] = array_values($mysqlValue[0]);
}
$return = array_merge(array($keys), $queryPlan);
}
}
return $return;
}
}

View File

@@ -0,0 +1,299 @@
# CakePHP DebugKit [![Build Status](https://secure.travis-ci.org/cakephp/debug_kit.png?branch=master)](http://travis-ci.org/cakephp/debug_kit)
DebugKit provides a debugging toolbar and enhanced debugging tools for CakePHP applications.
## Requirements
The master branch has the following requirements:
* CakePHP 2.2.0 or greater.
* PHP 5.3.0 or greater.
## Installation
_[Using [Composer](http://getcomposer.org/)]_
Add the plugin to your project's `composer.json` - something like this:
```javascript
{
"require": {
"cakephp/debug_kit": "2.2.*"
}
}
```
Because this plugin has the type `cakephp-plugin` set in it's own `composer.json`, composer knows to install it inside your `/Plugin` directory, rather than in the usual vendors file. It is recommended that you add `/Plugin/DebugKit` to your .gitignore file. (Why? [read this](http://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md).)
> Consider using "require-dev" if you only want to include DebugKit for your development environment.
_[Manual]_
* Download the [DebugKit archive](https://github.com/cakephp/debug_kit/zipball/2.2).
* Unzip that download.
* Rename the resulting folder to `DebugKit`
* Then copy this folder into `app/Plugin/`
_[GIT Submodule]_
In your app directory type:
```bash
git submodule add --branch 2.2 git://github.com/cakephp/debug_kit.git Plugin/DebugKit
git submodule init
git submodule update
```
_[GIT Clone]_
In your plugin directory type
```bash
git clone --single-branch --branch 2.2 git://github.com/cakephp/debug_kit.git DebugKit
```
### Enable plugin
* In 2.x you need to enable the plugin your `app/Config/bootstrap.php` file. If you are already using `CakePlugin::loadAll();`, then the following is not necessary.:
```php
CakePlugin::load('DebugKit');
```
* Include the toolbar component in your `app/Controller/AppController.php`:
```php
class AppController extends Controller {
public $components = array('DebugKit.Toolbar');
}
```
* Set `Configure::write('debug', 1);` in `app/Config/core.php`.
* Make sure to remove the 'sql_dump' element from your layout (usually
`app/View/Layouts/default.ctp`), if you want to experience the awesome that is
the DebugKit SQL log.
## Reporting Issues
If you have a problem with DebugKit please open an issue on [GitHub](https://github.com/cakephp/debug_kit/issues).
## Contributing
If you'd like to contribute to DebugKit, check out the
[roadmap](https://github.com/cakephp/debug_kit/wiki/roadmap) for any
planned features. You can [fork](https://help.github.com/articles/fork-a-repo)
the project, add features, and send [pull
requests](https://help.github.com/articles/using-pull-requests) or open
[issues](https://github.com/cakephp/debug_kit/issues).
## Versions
DebugKit has several releases, each compatible with different releases of
CakePHP. Use the appropriate version by downloading a tag, or checking out the
correct branch.
* `1.0, 1.1, 1.2` are compatible with CakePHP 1.2.x. These releases of DebugKit
will not work with CakePHP 1.3. You can also use the `1.2-branch` for the mos
recent updates and bugfixes.
* `1.3.0` is compatible with CakePHP 1.3.x only. It will not work with CakePHP
1.2. You can also use the `1.3` branch to get the most recent updates and
bugfixes.
* `2.0.0` is compatible with CakePHP 2.0.x only. It will not work with previous
CakePHP versions.
* `2.2.0` is compatible with CakePHP 2.2.0 and greater. It will not work with
older versions of CakePHP as this release uses new API's available in 2.2.
You can also use the `master` branch to get the most recent updates.
* `2.2.x` are compatible with CakePHP 2.2.0 and greater. It is a necessary
upgrade for people using CakePHP 2.4 as the naming conventions around loggers
changed in that release.
# Documentation
## Toolbar Panels
The DebugKit Toolbar is comprised of several panels, which are shown by clicking the
CakePHP icon in the upper right-hand corner of your browser after DebugKit has been
installed and loaded. Each panel is comprised of a panel class and view element.
Typically, a panel handles the collection and display of a single type of information
such as Logs or Request information. You can choose to panels from the toolbar or add
your own custom panels.
### Built-in Panels
There are several built-in panels, they are:
* **History** Allows access to previous request information, useful when
debugging actions with redirects.
* **Request** Displays information about the current request, GET, POST, Cake
Parameters, Current Route information and Cookies if the `CookieComponent`
is in you controller's components.
* **Session** Display the information currently in the Session.
* **Timer** Display any timers that were set during the request see
`DebugKitDebugger` for more information. Also displays
memory use at component callbacks as well as peak memory used.
* **Sql Logs** Displays sql logs for each database connection.
* **Log** Display any entries made to the log files this request.
* **Variables** Display View variables set in controller.
* **Environment** Display environment variables related to PHP + CakePHP.
## Configuration
The toolbar has a few configuration settings. Settings are passed in the component declaration like normal component configuration.
```php
public $components = array(
'DebugKit.Toolbar' => array(/* array of settings */)
);
```
### Configuring Panels
You can customize the toolbar to show your custom panels or hide any built-in panel when adding it toolbar to your components.
```php
public $components = array('DebugKit.Toolbar' => array(
'panels' => array('MyCustom', 'timer'=>false)
)
);
```
Would display your custom panel and all built-in panels except the 'Timer' panel.
#### Controlling Panels
Using the panels key you can specify which panels you want to load, as well as the order in which you want the panels loaded.
```php
public $components = array(
'DebugKit.Toolbar' => array('panels' => array('MyCustom', 'timer' => false))
);
```
Would add your custom panel `MyCustomPanel` to the toolbar and exclude the default `Timer` panel. In addition to choosing which panels you want, you can pass options into the `__construct` of the panels. For example the built-in `History` panel uses the `history` key to set the number of historical requests to track.
```php
public $components = array(
'DebugKit.Toolbar' => array('history' => 10)
);
```
Would load the `History` panel and set its history level to 10. The `panels` key is not passed to the Panel constructor.
#### forceEnable
The `forceEnable` setting is new in DebugKit 1.1. It allows you to force the toolbar to display regardless of the value of `Configure::read('debug');`. This is useful when profiling an application with debug kit as you can enable the toolbar even when running the application in production mode.
#### autoRun
autoRun is a new configuration setting for DebugKit 1.2. It allows you to control whether or not the toolbar is displayed automatically or whether you would like to use a query string parameter to enable it. Set this configuration key to false to use query string parameter toggling of the toolbar.
```php
public $components = array(
'DebugKit.Toolbar' => array('autoRun' => false)
);
```
When visiting a page you can add `?debug=true` to the url and the toolbar will be visible. Otherwise it will stay hidden and not execute.
## Developing Your Own Panels
You can create your own custom panels for DebugKit to help in debugging your applications.
### Panel Classes
Panel Classes simply need to be placed in`Panel` directory inside a `Lib` path. The filename should match the classname, so the class `MyCustomPanel` would be expected to have a filename of `app/Lib/Panel/MyCustomPanel.php`.
```php
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* My Custom Panel
*/
class MyCustomPanel extends DebugPanel {
...
}
```
See also the example `Test/test_app/Plugin/DebugkitTestPlugin/Lib/Panel/PluginTestPanel.php`.
Notice that custom panels are required to subclass the `DebugPanel` class. Panels can define the
`css` and `javascript` properties to include additional CSS or javascript on the page. Both
properties should be an array.
```php
class MyCustomPanel extends DebugPanel {
public $javascript = array(
'/my_plugin/js/custom_panel.js'
);
}
```
### Callbacks
Panel objects have 2 callbacks, that allow them to hook into and introspect on the current request.
```php
startup(Controller $controller)
```
Each panel's `startup()` method is called during component `startup()` process. `$controller` is a reference to the current controller object.
```php
beforeRender(Controller $controller)
```
Much like `startup()` `beforeRender()` is called during the Component beforeRender() process. Again `$controller` is a reference to the current controller. Normally at this point you could do additional introspection on the controller. The return of a panels `beforeRender()` is automatically passed to the View by the Toolbar Component. Therefore, under normal use you do not need to explicitly set variables to the controller.
#### Example of beforeRender Callback
```php
/**
* beforeRender callback - grabs request params
*
* @return array
*/
public function beforeRender(Controller $controller) {
return $controller->params;
}
```
This would return cake's internal params array. The return of a panel's `beforeRender()` is available in you Panel element as `$content`
### Panel Elements
Each Panel is expected to have a view element that renders the content from the panel. The element name must be the underscored inflection of the class name. For example `SessionPanel` has an element named `session_panel.ctp`, and sqllogPanel has an element named `sqllog_panel.ctp`. These elements should be located in the root of your `View/Elements` directory.
#### Custom Titles and Elements
Panels should pick up their title and element name by convention. However, if you need to choose a custom element name or title, there are properties to allow that configuration.
- `$title` - Set a custom title for use in the toolbar. This title will be used as the panels button.
- `$elementName` - Set a custom element name to be used to render the panel.
### Panels as Cake Plugins
Panels provided by [Cake Plugins](http://book.cakephp.org/2.0/en/plugins.html) work almost entirely the same as other plugins, with one minor difference: You must set `public $plugin` to be the name of the plugin directory, so that the panel's Elements can be located at render time.
```php
class MyCustomPanel extends DebugPanel {
public $plugin = 'MyPlugin';
...
}
```
To use a plugin panel, use the common CakePHP dot notation for plugins.
```php
public $components = array('DebugKit.Toolbar' => array(
'panels' => array('MyPlugin.MyCustom')
));
```
The above would load all the default panels as well as the custom panel from `MyPlugin`.
## Cache Engine
By default, DebugKit uses File as the engine for internal caching, but if you want to use another cache engine you can customize it by simply adding a cache key inside the components config array.
```php
public $components = array('DebugKit.Toolbar' => array(
'cache' => array('engine' => 'Memcache', 'servers' => array('127.0.0.1:11211'))
)
);
```
You can use any cache engine supported by CakePHP, the same way you set in both core.php and bootstrap.php files with the Cache::config() method.
## Viewing the Toolbar for AJAX Requests
When doing AJAX requests, you will not be able to see an HTML version of the toolbar. However, if you have a browser extension that supports FirePHP, you can view
the toolbar in your browser:
- [FirePHP 4 chrome](https://chrome.google.com/webstore/detail/firephp4chrome/gpgbmonepdpnacijbbdijfbecmgoojma)
- [FirePHP for chrome](https://chrome.google.com/webstore/detail/firephp-for-chrome/goajlbdffkligccnfgibeilhdnnpaead)
- [FirePHP for firefox](https://addons.mozilla.org/en-US/firefox/addon/firephp/)
Once you have installed the correct extension, you should see the toolbar data output on each AJAX request.

View File

@@ -0,0 +1,40 @@
<?php
/**
* View Group Test for DebugKit
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
require_once dirname(__FILE__) . DS . 'DebugkitGroupTestCase.php';
/**
* DebugKitViewTestSuite class
*
* @since DebugKit 1.0
*/
class AllDebugKitTest extends DebugKitGroupTestCase {
/**
* Assemble Test Suite
*
* @return PHPUnit_Framework_TestSuite the instance of PHPUnit_Framework_TestSuite
*/
public static function suite() {
$suite = new self;
$files = $suite->getTestFiles();
$suite->addTestFiles($files);
return $suite;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* View Group Test for DebugKit
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
require_once dirname(__FILE__) . DS . 'DebugkitGroupTestCase.php';
/**
* DebugKitViewTestSuite class
*
* @since DebugKit 1.0
*/
class AllDebugKitViewTest extends DebugkitGroupTestCase {
/**
* Assemble Test Suite
*
* @return PHPUnit_Framework_TestSuite the instance of PHPUnit_Framework_TestSuite
*/
public static function suite() {
$suite = new self;
$files = $suite->getTestFiles('View');
$suite->addTestFiles($files);
return $suite;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* View Group Test for DebugKit
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
require_once dirname(__FILE__) . DS . 'DebugkitGroupTestCase.php';
/**
* DebugKitViewTestSuite class
*
* @since DebugKit 1.0
*/
class AllDebugKitWithoutViewTest extends DebugkitGroupTestCase {
/**
* Assemble Test Suite
*
* @return PHPUnit_Framework_TestSuite the instance of PHPUnit_Framework_TestSuite
*/
public static function suite() {
$suite = new self;
$files = $suite->getTestFiles(null, 'View');
$suite->addTestFiles($files);
return $suite;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* AllTestsTest For DebugKit
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
require_once dirname(__FILE__) . DS . 'DebugkitGroupTestCase.php';
/**
* AllTestsTest class
*
* @since DebugKit 1.0
*/
class AllTestsTest extends DebugkitGroupTestCase {
/**
* Assemble Test Suite
*
* @return PHPUnit_Framework_TestSuite the instance of PHPUnit_Framework_TestSuite
*/
public static function suite() {
$suite = new self;
$files = $suite->getTestFiles();
$suite->addTestFiles($files);
return $suite;
}
}

View File

@@ -0,0 +1,524 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Router', 'Routing');
App::uses('Controller', 'Controller');
App::uses('AppController', 'Controller');
App::uses('Component', 'Controller');
App::uses('ToolbarComponent', 'DebugKit.Controller/Component');
App::uses('DebugMemory', 'DebugKit.Lib');
App::uses('DebugTimer', 'DebugKit.Lib');
/**
* Class TestToolbarComponent
*
* @since DebugKit 2.1
*/
class TestToolbarComponent extends ToolbarComponent {
/**
* Load Panels of Toolbar
*
* @param $panels
* @param array $settings
*/
public function loadPanels($panels, $settings = array()) {
$this->_loadPanels($panels, $settings);
}
}
/**
* ToolbarComponentTestCase Test case
*
*/
class ToolbarComponentTestCase extends CakeTestCase {
/**
* fixtures
*
* @var array
*/
public $fixtures = array('core.article');
/**
* url for test
*
* @var string
*/
public $url;
/**
* Start test callback
*
* @return void
*/
public function setUp() {
parent::setUp();
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
$this->_server = $_SERVER;
$this->_get = $_GET;
$this->_paths = array();
$this->_paths['plugins'] = App::path('plugins');
$this->_paths['views'] = App::path('views');
$this->_paths['vendors'] = App::path('vendors');
$this->_paths['controllers'] = App::path('controllers');
Configure::write('Cache.disable', false);
$this->url = '/';
}
/**
* endTest
*
* @return void
*/
public function tearDown() {
$_SERVER = $this->_server;
$_GET = $this->_get;
parent::tearDown();
App::build(array(
'plugins' => $this->_paths['plugins'],
'views' => $this->_paths['views'],
'controllers' => $this->_paths['controllers'],
'vendors' => $this->_paths['vendors']
), true);
Configure::write('Cache.disable', true);
unset($this->Controller);
ClassRegistry::flush();
if (class_exists('DebugMemory')) {
DebugMemory::clear();
}
if (class_exists('DebugTimer')) {
DebugTimer::clear();
}
Router::reload();
}
/**
* loading test controller
*
* @param array $settings
* @return Controller
*/
protected function _loadController($settings = array()) {
$request = new CakeRequest($this->url);
$request->addParams(Router::parse($this->url));
$this->Controller = new Controller($request);
$this->Controller->uses = null;
$this->Controller->components = array('Toolbar' => $settings + array('className' => 'TestToolbar'));
$this->Controller->constructClasses();
$this->Controller->Components->trigger('initialize', array($this->Controller));
return $this->Controller;
}
/**
* test Loading of panel classes
*
* @return void
*/
public function testLoadPanels() {
$this->_loadController();
$this->Controller->Toolbar->loadPanels(array('session', 'request'));
$this->assertInstanceOf('SessionPanel', $this->Controller->Toolbar->panels['session']);
$this->assertInstanceOf('RequestPanel', $this->Controller->Toolbar->panels['request']);
$this->Controller->Toolbar->loadPanels(array('history'), array('history' => 10));
$this->assertEquals($this->Controller->Toolbar->panels['history']->history, 10);
}
/**
* Test exceptions on bad panel names
*
* @expectedException PHPUnit_Framework_Error
* @return void
*/
public function testLoadPanelsError() {
$this->Controller->Toolbar->loadPanels(array('randomNonExisting', 'request'));
}
/**
* test Loading of panel classes from a plugin
*
* @return void
*/
public function testLoadPluginPanels() {
$debugKitPath = App::pluginPath('DebugKit');
$noDir = (empty($debugKitPath) || !file_exists($debugKitPath));
if ($noDir) {
$this->markTestAsSkipped('Could not find DebugKit in plugin paths');
}
App::build(array(
'Plugin' => array($debugKitPath . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
));
CakePlugin::load('DebugkitTestPlugin');
$this->_loadController();
$this->Controller->Toolbar->loadPanels(array('DebugkitTestPlugin.PluginTest'));
$this->assertInstanceOf(
'PluginTestPanel',
$this->Controller->Toolbar->panels['plugin_test']
);
}
/**
* test loading of vendor panels from test_app folder
*
* @return void
*/
public function testLibPanels() {
$debugKitPath = App::pluginPath('DebugKit');
$noDir = (empty($debugKitPath) || !file_exists($debugKitPath));
if ($noDir) {
$this->markTestAsSkipped('Could not find DebugKit in plugin paths');
}
App::build(array(
'Lib' => array($debugKitPath . 'Test' . DS . 'test_app' . DS . 'Lib' . DS)
));
$this->_loadController(array(
'panels' => array('test'),
'className' => 'DebugKit.Toolbar',
));
$this->assertTrue(isset($this->Controller->Toolbar->panels['test']));
$this->assertInstanceOf('TestPanel', $this->Controller->Toolbar->panels['test']);
}
/**
* test construct
*
* @return void
*/
public function testConstruct() {
$this->_loadController();
$this->assertFalse(empty($this->Controller->Toolbar->panels));
$memory = DebugMemory::getAll();
$this->assertTrue(isset($memory['Component initialization']));
$events = $this->Controller->getEventManager();
$this->assertNotEmpty($events->listeners('Controller.initialize'));
$this->assertNotEmpty($events->listeners('Controller.startup'));
$this->assertNotEmpty($events->listeners('Controller.beforeRender'));
$this->assertNotEmpty($events->listeners('Controller.shutdown'));
$this->assertNotEmpty($events->listeners('View.beforeRender'));
$this->assertNotEmpty($events->listeners('View.afterRender'));
$this->assertNotEmpty($events->listeners('View.beforeLayout'));
$this->assertNotEmpty($events->listeners('View.afterLayout'));
}
/**
* test initialize w/ custom panels and defaults
*
* @return void
*/
public function testInitializeCustomPanelsWithDefaults() {
$this->_loadController(array(
'panels' => array('test'),
));
$expected = array(
'history', 'session', 'request', 'sql_log', 'timer',
'log', 'variables', 'environment', 'include', 'test'
);
$this->assertEquals($expected, array_keys($this->Controller->Toolbar->panels));
}
/**
* test syntax for removing panels
*
* @return void
*/
public function testInitializeRemovingPanels() {
$this->_loadController(array(
'panels' => array(
'session' => false,
'history' => false,
)
));
$expected = array('request', 'sql_log', 'timer', 'log', 'variables', 'environment', 'include');
$this->assertEquals($expected, array_keys($this->Controller->Toolbar->panels));
}
/**
* ensure that Toolbar is not enabled when debug == 0 on initialize
*
* @return void
*/
public function testDebugDisableOnInitialize() {
$_debug = Configure::read('debug');
Configure::write('debug', 0);
$this->_loadController();
Configure::write('debug', $_debug);
$this->assertFalse($this->Controller->Components->enabled('Toolbar'));
}
/**
* test that passing in forceEnable will enable the toolbar even if debug = 0
*
* @return void
*/
public function testForceEnable() {
$_debug = Configure::read('debug');
Configure::write('debug', 0);
$this->_loadController(array(
'forceEnable' => true,
));
Configure::write('debug', $_debug);
$this->assertTrue($this->Controller->Components->enabled('Toolbar'));
}
/**
* Test disabling autoRunning of toolbar
*
* @return void
*/
public function testAutoRunSettingFalse() {
$this->_loadController(array(
'autoRun' => false,
));
$this->assertFalse($this->Controller->Components->enabled('Toolbar'));
}
/**
* test autorun = false with query string param
*
* @return void
*/
public function testAutoRunSettingWithQueryString() {
$this->url = '/?debug=1';
$_GET['debug'] = 1;
$this->_loadController(array(
'autoRun' => false,
));
$this->assertTrue($this->Controller->Components->enabled('Toolbar'));
}
/**
* test startup
*
* @return void
*/
public function testStartup() {
$this->_loadController(array(
'panels' => array('timer'),
));
$MockPanel = $this->getMock('DebugPanel');
$MockPanel->expects($this->once())->method('startup');
$this->Controller->Toolbar->panels['timer'] = $MockPanel;
$this->Controller->Toolbar->startup($this->Controller);
$timers = DebugTimer::getAll();
$this->assertTrue(isset($timers['controllerAction']));
$memory = DebugMemory::getAll();
$this->assertTrue(isset($memory['Controller action start']));
}
/**
* Test that cache config generation works.
*
* @return void
*/
public function testCacheConfigGeneration() {
$this->_loadController();
$this->Controller->Components->trigger('startup', array($this->Controller));
$results = Cache::config('debug_kit');
$this->assertTrue(is_array($results));
}
/**
* test state saving of toolbar
*
* @return void
*/
public function testStateSaving() {
$this->_loadController();
$configName = 'debug_kit';
$this->Controller->Toolbar->cacheKey = 'toolbar_history';
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->set('test', 'testing');
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$result = Cache::read('toolbar_history', $configName);
$this->assertEquals($result[0]['variables']['content']['test'], 'testing');
Cache::delete('toolbar_history', $configName);
}
/**
* Test Before Render callback
*
* @return void
*/
public function testBeforeRender() {
$this->_loadController(array(
'panels' => array('timer', 'session'),
));
$MockPanel = $this->getMock('DebugPanel');
$MockPanel->expects($this->once())->method('beforeRender');
$this->Controller->Toolbar->panels['timer'] = $MockPanel;
$this->Controller->Toolbar->beforeRender($this->Controller);
$this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar']));
$this->assertEquals($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.HtmlToolbar');
$this->assertEquals($this->Controller->helpers['DebugKit.Toolbar']['cacheConfig'], 'debug_kit');
$this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar']['cacheKey']));
$this->assertTrue(isset($this->Controller->viewVars['debugToolbarPanels']));
$vars = $this->Controller->viewVars['debugToolbarPanels'];
$expected = array(
'plugin' => 'DebugKit',
'elementName' => 'session_panel',
'content' => $this->Controller->Toolbar->Session->read(),
'disableTimer' => true,
'title' => ''
);
$this->assertEquals($expected, $vars['session']);
$memory = DebugMemory::getAll();
$this->assertTrue(isset($memory['Controller render start']));
}
/**
* test that vars are gathered and state is saved on beforeRedirect
*
* @return void
*/
public function testBeforeRedirect() {
$this->_loadController(array(
'panels' => array('session', 'history'),
));
$configName = 'debug_kit';
$this->Controller->Toolbar->cacheKey = 'toolbar_history';
Cache::delete('toolbar_history', $configName);
DebugTimer::start('controllerAction', 'testing beforeRedirect');
$MockPanel = $this->getMock('DebugPanel');
$MockPanel->expects($this->once())->method('beforeRender');
$this->Controller->Toolbar->panels['session'] = $MockPanel;
$this->Controller->Toolbar->beforeRedirect($this->Controller, '/another/url');
$result = Cache::read('toolbar_history', $configName);
$this->assertTrue(isset($result[0]['session']));
$this->assertFalse(isset($result[0]['history']));
$timers = DebugTimer::getAll();
$this->assertTrue(isset($timers['controllerAction']));
}
/**
* test that loading state (accessing cache) works.
*
* @return void
*/
public function testLoadState() {
$this->_loadController();
$this->Controller->Toolbar->cacheKey = 'toolbar_history';
$data = array(0 => array('my data'));
Cache::write('toolbar_history', $data, 'debug_kit');
$result = $this->Controller->Toolbar->loadState(0);
$this->assertEquals($result, $data[0]);
}
/**
* Test that history state urls set prefix = null and admin = null so generated urls do not
* adopt these params.
*
* @return void
*/
public function testHistoryUrlGenerationWithPrefixes() {
$this->url = '/debugkit_url_with_prefixes_test';
Router::connect($this->url, array(
'controller' => 'posts',
'action' => 'edit',
'admin' => 1,
'prefix' => 'admin',
'plugin' => 'cms',
));
$this->_loadController();
$this->Controller->Toolbar->cacheKey = 'url_test';
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$result = $this->Controller->Toolbar->panels['history']->beforeRender($this->Controller);
$expected = array(
'plugin' => 'debug_kit',
'controller' => 'toolbar_access',
'action' => 'history_state',
0 => 1,
'admin' => false,
);
$this->assertEquals($result[0]['url'], $expected);
Cache::delete('url_test', 'debug_kit');
}
/**
* Test that the FireCake toolbar is used on AJAX requests
*
* @return void
*/
public function testAjaxToolbar() {
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
$this->_loadController();
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$this->assertEquals($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.FirePhpToolbar');
}
/**
* Test that the toolbar does not interfere with requestAction
*
* @return void
*/
public function testNoRequestActionInterference() {
$debugKitPath = App::pluginPath('DebugKit');
$noDir = (empty($debugKitPath) || !file_exists($debugKitPath));
if ($noDir) {
$this->markTestAsSkipped('Could not find DebugKit in plugin paths');
}
App::build(array(
'Controller' => $debugKitPath . 'Test' . DS . 'test_app' . DS . 'Controller' . DS,
'View' => array(
$debugKitPath . 'Test' . DS . 'test_app' . DS . 'View' . DS,
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'View' . DS
),
'plugins' => $this->_paths['plugins']
));
Router::reload();
$this->_loadController();
$result = $this->Controller->requestAction('/debug_kit_test/request_action_return', array('return'));
$this->assertEquals($result, 'I am some value from requestAction.');
$result = $this->Controller->requestAction('/debug_kit_test/request_action_render', array('return'));
$this->assertEquals($result, 'I have been rendered.');
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* DebugKit Group Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Class DebugKitGroupTestCase
*
*/
class DebugKitGroupTestCase extends PHPUnit_Framework_TestSuite {
/**
* Constructor
*/
public function __construct() {
$label = Inflector::humanize(Inflector::underscore(get_class($this)));
parent::__construct($label);
}
/**
* Get Test Files
*
* @param null $directory
* @param null $excludes
* @return array
*/
public static function getTestFiles($directory = null, $excludes = null) {
if (is_array($directory)) {
$files = array();
foreach ($directory as $d) {
$files = array_merge($files, self::getTestFiles($d, $excludes));
}
return array_unique($files);
}
if ($excludes !== null) {
$excludes = self::getTestFiles((array)$excludes);
}
if ($directory === null || $directory !== realpath($directory)) {
$basePath = App::pluginPath('DebugKit') . 'Test' . DS . 'Case' . DS;
$directory = str_replace(DS . DS, DS, $basePath . $directory);
}
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
$files = array();
while ($it->valid()) {
if (!$it->isDot()) {
$file = $it->key();
if (
preg_match('|Test\.php$|', $file) &&
$file !== __FILE__ &&
!preg_match('|^All.+?\.php$|', basename($file)) &&
($excludes === null || !in_array($file, $excludes))
) {
$files[] = $file;
}
}
$it->next();
}
return $files;
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* DebugKit Debugger Test Case File
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since debug_kit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
App::uses('DebugKitDebugger', 'DebugKit.Lib');
require_once CakePlugin::path('DebugKit') . 'Test' . DS . 'Case' . DS . 'TestFireCake.php';
/**
* Test case for the DebugKitDebugger
*
* @since debug_kit 0.1
*/
class DebugKitDebuggerTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
Configure::write('log', false);
$this->firecake = FireCake::getInstance('TestFireCake');
TestFireCake::reset();
}
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
Configure::write('log', true);
DebugKitDebugger::clearTimers();
TestFireCake::reset();
}
/**
* test output switch to firePHP
*
* @return void
*/
public function testOutput() {
Debugger::getInstance('DebugKitDebugger');
Debugger::addFormat('fb', array('callback' => 'DebugKitDebugger::fireError'));
Debugger::outputAs('fb');
set_error_handler('ErrorHandler::handleError');
$foo .= '';
restore_error_handler();
$result = $this->firecake->sentHeaders;
$this->assertRegExp('/GROUP_START/', $result['X-Wf-1-1-1-1']);
$this->assertRegExp('/ERROR/', $result['X-Wf-1-1-1-2']);
$this->assertRegExp('/GROUP_END/', $result['X-Wf-1-1-1-5']);
Debugger::getInstance('Debugger');
Debugger::outputAs('html');
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* DebugKit Debug Memory Test Cases
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
App::uses('DebugMemory', 'DebugKit.Lib');
/**
* Class DebugMemoryTest
*
*/
class DebugMemoryTest extends CakeTestCase {
/**
* test memory usage
*
* @return void
*/
public function testMemoryUsage() {
$result = DebugMemory::getCurrent();
$this->assertTrue(is_int($result));
$result = DebugMemory::getPeak();
$this->assertTrue(is_int($result));
}
/**
* test making memory use markers.
*
* @return void
*/
public function testMemorySettingAndGetting() {
DebugMemory::clear();
$result = DebugMemory::record('test marker');
$this->assertTrue($result);
$result = DebugMemory::getAll(true);
$this->assertEquals(count($result), 1);
$this->assertTrue(isset($result['test marker']));
$this->assertTrue(is_numeric($result['test marker']));
$result = DebugMemory::getAll();
$this->assertTrue(empty($result));
DebugMemory::record('test marker');
DebugMemory::record('test marker');
$result = DebugMemory::getAll();
$this->assertEquals(count($result), 2);
$this->assertTrue(isset($result['test marker']));
$this->assertTrue(isset($result['test marker #2']));
}
}

View File

@@ -0,0 +1,169 @@
<?php
/**
* DebugTimer Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since debug_kit 2.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugTimer', 'DebugKit.Lib');
/**
* Class DebugTimerTest
*
* @since debug_kit 2.0
*/
class DebugTimerTest extends CakeTestCase {
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
DebugTimer::clear();
}
/**
* Start Timer test
*
* @return void
*/
public function testTimers() {
$this->assertTrue(DebugTimer::start('test1', 'this is my first test'));
usleep(5000);
$this->assertTrue(DebugTimer::stop('test1'));
$elapsed = DebugTimer::elapsedTime('test1');
$this->assertTrue($elapsed > 0.0050);
$this->assertTrue(DebugTimer::start('test2', 'this is my second test'));
sleep(1);
$this->assertTrue(DebugTimer::stop('test2'));
$elapsed = DebugTimer::elapsedTime('test2');
$expected = stripos(PHP_OS, 'win') === false ? 0.999: 0.95; // Windows timer's precision is bad
$this->assertTrue($elapsed >= $expected);
DebugTimer::start('test3');
$this->assertIdentical(DebugTimer::elapsedTime('test3'), 0);
$this->assertFalse(DebugTimer::stop('wrong'));
}
/**
* test timers with no names.
*
* @return void
*/
public function testAnonymousTimers() {
$this->assertTrue(DebugTimer::start());
usleep(2000);
$this->assertTrue(DebugTimer::stop());
$timers = DebugTimer::getAll();
$this->assertEquals(2, count($timers));
end($timers);
$key = key($timers);
$lineNo = __LINE__ - 8;
$file = Debugger::trimPath(__FILE__);
$expected = $file . ' line ' . $lineNo;
$this->assertEquals($expected, $key);
$timer = $timers[$expected];
$this->assertTrue($timer['time'] > 0.0020);
$this->assertEquals($expected, $timers[$expected]['message']);
}
/**
* Assert that nested anonymous timers don't get mixed up.
*
* @return void
*/
public function testNestedAnonymousTimers() {
$this->assertTrue(DebugTimer::start());
usleep(100);
$this->assertTrue(DebugTimer::start());
usleep(100);
$this->assertTrue(DebugTimer::stop());
$this->assertTrue(DebugTimer::stop());
$timers = DebugTimer::getAll();
$this->assertEquals(3, count($timers), 'incorrect number of timers %s');
$firstTimerLine = __LINE__ - 9;
$secondTimerLine = __LINE__ - 8;
$file = Debugger::trimPath(__FILE__);
$this->assertTrue(isset($timers[$file . ' line ' . $firstTimerLine]), 'first timer is not set %s');
$this->assertTrue(isset($timers[$file . ' line ' . $secondTimerLine]), 'second timer is not set %s');
$firstTimer = $timers[$file . ' line ' . $firstTimerLine];
$secondTimer = $timers[$file . ' line ' . $secondTimerLine];
$this->assertTrue($firstTimer['time'] > $secondTimer['time']);
}
/**
* test that calling start with the same name does not overwrite previous timers
* and instead adds new ones.
*
* @return void
*/
public function testRepeatTimers() {
DebugTimer::start('my timer', 'This is the first call');
usleep(100);
DebugTimer::start('my timer', 'This is the second call');
usleep(100);
DebugTimer::stop('my timer');
DebugTimer::stop('my timer');
$timers = DebugTimer::getAll();
$this->assertEquals(3, count($timers), 'wrong timer count %s');
$this->assertTrue(isset($timers['my timer']));
$this->assertTrue(isset($timers['my timer #2']));
$this->assertTrue($timers['my timer']['time'] > $timers['my timer #2']['time'], 'timer 2 is longer? %s');
$this->assertEquals('This is the first call', $timers['my timer']['message']);
$this->assertEquals('This is the second call #2', $timers['my timer #2']['message']);
}
/**
* testRequestTime
*
* @return void
*/
public function testRequestTime() {
$result1 = DebugTimer::requestTime();
usleep(50);
$result2 = DebugTimer::requestTime();
$this->assertTrue($result1 < $result2);
}
/**
* test getting all the set timers.
*
* @return void
*/
public function testGetTimers() {
DebugTimer::start('test1', 'this is my first test');
DebugTimer::stop('test1');
usleep(50);
DebugTimer::start('test2');
DebugTimer::stop('test2');
$timers = DebugTimer::getAll();
$this->assertEquals(3, count($timers));
$this->assertTrue(is_float($timers['test1']['time']));
$this->assertTrue(isset($timers['test1']['message']));
$this->assertTrue(isset($timers['test2']['message']));
}
}

View File

@@ -0,0 +1,345 @@
<?php
/**
* CakeFirePHP Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
App::uses('FireCake', 'DebugKit.Lib');
require_once CakePlugin::path('DebugKit') . 'Test' . DS . 'Case' . DS . 'TestFireCake.php';
/**
* Test Case For FireCake
*
* @since DebugKit 0.1
*/
class FireCakeTestCase extends CakeTestCase {
/**
* setup test
*
* Fill FireCake with TestFireCake instance.
*
* @return void
*/
public function setUp() {
$this->firecake = FireCake::getInstance('TestFireCake');
TestFireCake::reset();
}
/**
* Reset the FireCake counters and headers.
*
* @return void
*/
public function tearDown() {
TestFireCake::reset();
}
/**
* Test getInstance cheat.
*
* If this fails the rest of the test is going to fail too.
*
* @return void
*/
public function testGetInstanceOverride() {
$instance = FireCake::getInstance();
$instance2 = FireCake::getInstance();
$this->assertReference($instance, $instance2);
$this->assertIsA($instance, 'FireCake');
$this->assertIsA($instance, 'TestFireCake', 'Stored instance is not a copy of TestFireCake, test case is broken.');
}
/**
* Test setOptions
*
* @return void
*/
public function testSetOptions() {
FireCake::setOptions(array('includeLineNumbers' => false));
$this->assertEquals($this->firecake->options['includeLineNumbers'], false);
}
/**
* Test Log()
*
* @return void
*/
public function testLog() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::log('Testing');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '26|[{"Type":"LOG"},"Testing"]|');
FireCake::log('Testing', 'log-info');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"LOG","Label":"log-info"},"Testing"]|');
}
/**
* Test info()
*
* @return void
*/
public function testInfo() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::info('I have information');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '38|[{"Type":"INFO"},"I have information"]|');
FireCake::info('I have information', 'info-label');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '59|[{"Type":"INFO","Label":"info-label"},"I have information"]|');
}
/**
* Test info()
*
* @return void
*/
public function testWarn() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::warn('A Warning');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"WARN"},"A Warning"]|');
FireCake::warn('A Warning', 'Bzzz');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '44|[{"Type":"WARN","Label":"Bzzz"},"A Warning"]|');
}
/**
* Test error()
*
* @return void
*/
public function testError() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::error('An error');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"ERROR"},"An error"]|');
FireCake::error('An error', 'wonky');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"ERROR","Label":"wonky"},"An error"]|');
}
/**
* Test dump()
*
* @return void
*/
public function testDump() {
FireCake::dump('mydump', array('one' => 1, 'two' => 2));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-2-1-1'], '28|{"mydump":{"one":1,"two":2}}|');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-2']));
}
/**
* Test table() generation
*
* @return void
*/
public function testTable() {
$table[] = array('Col 1 Heading','Col 2 Heading');
$table[] = array('Row 1 Col 1','Row 1 Col 2');
$table[] = array('Row 2 Col 1','Row 2 Col 2');
$table[] = array('Row 3 Col 1','Row 3 Col 2');
FireCake::table('myTrace', $table);
$expected = '162|[{"Type":"TABLE","Label":"myTrace"},[["Col 1 Heading","Col 2 Heading"],["Row 1 Col 1","Row 1 Col 2"],["Row 2 Col 1","Row 2 Col 2"],["Row 3 Col 1","Row 3 Col 2"]]]|';
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], $expected);
}
/**
* TestStringEncoding
*
* @return void
*/
public function testStringEncode() {
$vars = array(1,2,3);
$result = $this->firecake->stringEncode($vars);
$this->assertEquals($result, array(1,2,3));
$this->firecake->setOptions(array('maxArrayDepth' => 3));
$deep = array(1 => array(2 => array(3)));
$result = $this->firecake->stringEncode($deep);
$this->assertEquals($result, array(1 => array(2 => '** Max Array Depth (3) **')));
}
/**
* Test object encoding
*
* @return void
*/
public function testStringEncodeObjects() {
$obj = FireCake::getInstance();
$result = $this->firecake->stringEncode($obj);
$this->assertTrue(is_array($result));
$this->assertEquals($result['_defaultOptions']['useNativeJsonEncode'], true);
$this->assertEquals($result['_encodedObjects'][0], '** Recursion (TestFireCake) **');
}
/**
* Test trace()
*
* @return void
*/
public function testTrace() {
FireCake::trace('myTrace');
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
$this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
$dump = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
$this->assertPattern('/"Message":"myTrace"/', $dump);
$this->assertPattern('/"Trace":\[/', $dump);
}
/**
* Test enabling and disabling of FireCake output
*
* @return void
*/
public function testEnableDisable() {
FireCake::disable();
FireCake::trace('myTrace');
$this->assertTrue(empty($this->firecake->sentHeaders));
FireCake::enable();
FireCake::trace('myTrace');
$this->assertFalse(empty($this->firecake->sentHeaders));
}
/**
* Test correct line continuation markers on multi line headers.
*
* @return void
*/
public function testMultiLineOutput() {
FireCake::trace('myTrace');
$this->assertGreaterThan(1, $this->firecake->sentHeaders['X-Wf-1-Index']);
$header = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
$this->assertEquals(substr($header, -2), '|\\');
$endIndex = $this->firecake->sentHeaders['X-Wf-1-Index'];
$header = $this->firecake->sentHeaders['X-Wf-1-1-1-' . $endIndex];
$this->assertEquals(substr($header, -1), '|');
}
/**
* Test inclusion of line numbers
*
* @return void
*/
public function testIncludeLineNumbers() {
FireCake::setOptions(array('includeLineNumbers' => true));
FireCake::info('Testing');
$result = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
$this->assertPattern('/"File"\:".*FireCakeTest.php/', $result);
$this->assertPattern('/"Line"\:\d+/', $result);
}
/**
* Test Group messages
*
* @return void
*/
public function testGroup() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::group('test');
FireCake::info('my info');
FireCake::groupEnd();
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '63|[{"Collapsed":"true","Type":"GROUP_START","Label":"test"},null]|');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '27|[{"Type":"GROUP_END"},null]|');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 3);
}
/**
* Test fb() parameter parsing
*
* @return void
*/
public function testFbParameterParsing() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::fb('Test');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '23|[{"Type":"LOG"},"Test"]|');
FireCake::fb('Test', 'warn');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '24|[{"Type":"WARN"},"Test"]|');
FireCake::fb('Test', 'Custom label', 'warn');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '47|[{"Type":"WARN","Label":"Custom label"},"Test"]|');
$this->expectError('PHPUnit_Framework_Error');
$this->assertFalse(FireCake::fb('Test', 'Custom label', 'warn', 'more parameters'));
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-Index'], 3);
}
/**
* Test defaulting to log if incorrect message type is used
*
* @return void
*/
public function testIncorrectMessageType() {
FireCake::setOptions(array('includeLineNumbers' => false));
FireCake::fb('Hello World', 'foobared');
$this->assertEquals($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '30|[{"Type":"LOG"},"Hello World"]|');
}
/**
* Test DetectClientExtension.
*
* @return void
*/
public function testDetectClientExtension() {
$back = env('HTTP_USER_AGENT');
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.2.1';
$this->assertTrue(FireCake::detectClientExtension());
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.0.4';
$this->assertFalse(FireCake::detectClientExtension());
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4';
$this->assertFalse(FireCake::detectClientExtension());
$_SERVER['HTTP_USER_AGENT'] = $back;
}
/**
* Test of Non Native JSON encoding.
*
* @return void
*/
public function testNonNativeEncoding() {
FireCake::setOptions(array('useNativeJsonEncode' => false));
$json = FireCake::jsonEncode(array('one' => 1, 'two' => 2));
$this->assertEquals($json, '{"one":1,"two":2}');
$json = FireCake::jsonEncode(array(1,2,3));
$this->assertEquals($json, '[1,2,3]');
$json = FireCake::jsonEncode(FireCake::getInstance());
$this->assertPattern('/"options"\:\{"maxObjectDepth"\:\d*,/', $json);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* DebugKit Log Panel Test Cases
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
App::uses('LogPanel', 'DebugKit.Lib/Panel');
App::uses('Controller', 'Controller');
/**
* Class LogPanelTest
*
*/
class LogPanelTest extends CakeTestCase {
/**
* set up
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->panel = new LogPanel();
}
/**
* Test that logging configs are created.
*
* @return void
*/
public function testConstructor() {
$result = CakeLog::configured();
$this->assertContains('debug_kit_log_panel', $result);
$this->assertTrue(count($result) > 1, 'Default loggers were not added.');
}
/**
* testBeforeRender
*
* @return void
*/
public function testBeforeRender() {
$controller = new Controller();
CakeLog::write('error', 'Test');
$result = $this->panel->beforeRender($controller);
$this->assertInstanceOf('DebugKitLog', $result);
$this->assertTrue(isset($result->logs));
$this->assertCount(1, $result->logs['error']);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* SqlLogPanelTest
*
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('SqlLogPanel', 'DebugKit.Lib/Panel');
App::uses('Model', 'Model');
App::uses('Controller', 'Controller');
/**
* Class SqlLogPanelTest
*
* @since DebugKit 2.1
*/
class SqlLogPanelTest extends CakeTestCase {
/**
* fixtures.
*
* @var array
*/
public $fixtures = array('core.article');
/**
* Setup
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->panel = new SqlLogPanel();
}
/**
* test the parsing of source list.
*
* @return void
*/
public function testBeforeRender() {
$Article = ClassRegistry::init('Article');
$Article->find('first', array('conditions' => array('Article.id' => 1)));
$controller = new Controller();
$result = $this->panel->beforeRender($controller);
$this->assertTrue(isset($result['connections'][$Article->useDbConfig]));
$this->assertTrue(isset($result['threshold']));
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* DebugKit TimedBehavior Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.3
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugKitDebugger', 'DebugKit.Lib');
/**
* Class TimedBehaviorTestCase
*
* @since DebugKit 1.3
*/
class TimedBehaviorTestCase extends CakeTestCase {
/**
* Fixtures
*
* @var array
*/
public $fixtures = array('core.article');
/**
* Start Test callback
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->Article = ClassRegistry::init('Article');
$this->Article->Behaviors->attach('DebugKit.Timed');
}
/**
* End a test
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Article);
ClassRegistry::flush();
DebugKitDebugger::clearTimers();
}
/**
* Test find timers
*
* @return void
*/
public function testFindTimers() {
$timers = DebugKitDebugger::getTimers(false);
$this->assertEquals(count($timers), 1);
$this->Article->find('all');
$result = DebugKitDebugger::getTimers(false);
$this->assertEquals(count($result), 2);
$this->Article->find('all');
$result = DebugKitDebugger::getTimers(false);
$this->assertEquals(count($result), 3);
}
/**
* Test save timers
*
* @return void
*/
public function testSaveTimers() {
$timers = DebugKitDebugger::getTimers(false);
$this->assertEquals(count($timers), 1);
$this->Article->save(array('user_id' => 1, 'title' => 'test', 'body' => 'test'));
$result = DebugKitDebugger::getTimers(false);
$this->assertEquals(count($result), 2);
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* DebugKit ToolbarAccess Model Test case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.3
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
App::uses('ToolbarAccess', 'DebugKit.Model');
/**
* Test case for ToolbarAccess model
*
* @since DebugKit 1.3
*/
class ToolbarAccessTestCase extends CakeTestCase {
/**
* Included fixtures
*
* @var array
*/
public $fixtures = array('core.post');
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->Model = new ToolbarAccess();
}
/**
* tearDown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Model);
}
/**
* test that explain query returns arrays of query information.
*
* @return void
*/
public function testExplainQuery() {
$Post = new CakeTestModel(array('table' => 'posts', 'alias' => 'Post'));
$db = $Post->getDataSource();
$sql = 'SELECT * FROM ' . $db->fullTableName('posts') . ';';
$result = $this->Model->explainQuery($Post->useDbConfig, $sql);
$this->assertTrue(is_array($result));
$this->assertFalse(empty($result));
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Common test objects used in DebugKit tests
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('FireCake', 'DebugKit.Lib');
/**
* TestFireCake class allows for testing of FireCake
*
* @since DebugKit 0.1
*/
class TestFireCake extends FireCake {
/**
* Headers that were sent
*
* @var array
*/
public $sentHeaders = array();
/**
* Send header
*
* @param $name
* @param $value
*/
protected function _sendHeader($name, $value) {
$_this = FireCake::getInstance();
$_this->sentHeaders[$name] = $value;
}
/**
* Skip client detection as headers are not being sent.
*
* @return boolean Always true
*/
public static function detectClientExtension() {
return true;
}
/**
* Reset FireCake
*
* @return void
*/
public static function reset() {
$_this = FireCake::getInstance();
$_this->sentHeaders = array();
$_this->_messageIndex = 1;
}
}

View File

@@ -0,0 +1,152 @@
<?php
/**
* Toolbar Abstract Helper Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
$path = CakePlugin::path('DebugKit');
App::uses('View', 'View');
App::uses('Controller', 'Controller');
App::uses('CakeResponse', 'Network');
App::uses('Router', 'Routing');
App::uses('ToolbarHelper', 'DebugKit.View/Helper');
App::uses('FirePhpToolbarHelper', 'DebugKit.View/Helper');
require_once $path . 'Test' . DS . 'Case' . DS . 'TestFireCake.php';
/**
* Class FirePhpToolbarHelperTestCase
*
* @since DebugKit 0.1
*/
class FirePhpToolbarHelperTestCase extends CakeTestCase {
/**
* setUp
*
* @return void
**/
public function setUp() {
parent::setUp();
Router::connect('/:controller/:action');
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::parse('/');
$this->Controller = new Controller($this->getMock('CakeRequest'), new CakeResponse());
$this->View = new View($this->Controller);
$this->Toolbar = new ToolbarHelper($this->View, array('output' => 'DebugKit.FirePhpToolbar'));
$this->Toolbar->FirePhpToolbar = new FirePhpToolbarHelper($this->View);
$this->firecake = FireCake::getInstance('TestFireCake');
TestFireCake::reset();
}
/**
* Start test - switch view paths
*
* @return void
**/
public static function setupBeforeClass() {
App::build(array(
'View' => array(
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Test' . DS . 'test_app' . DS . 'View' . DS,
APP . 'Plugin' . DS . 'DebugKit' . DS . 'View' . DS,
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'View' . DS
)), true);
}
/**
* End Test
*
* @return void
*/
public static function tearDownAfterClass() {
App::build();
}
/**
* TearDown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Toolbar, $this->Controller);
TestFireCake::reset();
}
/**
* Test neat array (dump)creation
*
* @return void
*/
public function testMakeNeatArray() {
$this->Toolbar->makeNeatArray(array(1,2,3));
$result = $this->firecake->sentHeaders;
$this->assertTrue(isset($result['X-Wf-1-1-1-1']));
$this->assertRegexp('/\[1,2,3\]/', $result['X-Wf-1-1-1-1']);
}
/**
* Test afterlayout element rendering
*
* @return void
*/
public function testAfterLayout() {
$this->Controller->viewPath = 'Posts';
$request = new CakeRequest('/posts/index');
$request->addParams(Router::parse($request->url));
$request->addPaths(array(
'webroot' => '/',
'base' => '/',
'here' => '/posts/index',
));
$this->Controller->setRequest($request);
$this->Controller->layout = 'default';
$this->Controller->uses = null;
$this->Controller->components = array('DebugKit.Toolbar');
$this->Controller->constructClasses();
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$result = $this->Controller->render();
$this->assertNotRegExp('/debug-toolbar/', (string)$result);
$result = $this->firecake->sentHeaders;
$this->assertTrue(is_array($result));
}
/**
* test starting a panel
*
* @return void
**/
public function testPanelStart() {
$this->Toolbar->panelStart('My Panel', 'my_panel');
$result = $this->firecake->sentHeaders;
$this->assertPattern('/GROUP_START.+My Panel/', $result['X-Wf-1-1-1-1']);
}
/**
* test ending a panel
*
* @return void
**/
public function testPanelEnd() {
$this->Toolbar->panelEnd();
$result = $this->firecake->sentHeaders;
$this->assertPattern('/GROUP_END/', $result['X-Wf-1-1-1-1']);
}
}

View File

@@ -0,0 +1,452 @@
<?php
/**
* Toolbar HTML Helper Test Case
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('View', 'View');
App::uses('Controller', 'Controller');
App::uses('Router', 'Routing');
App::uses('CakeResponse', 'Network');
App::uses('ToolbarHelper', 'DebugKit.View/Helper');
App::uses('HtmlToolbarHelper', 'DebugKit.View/Helper');
App::uses('HtmlHelper', 'View/Helper');
App::uses('FormHelper', 'View/Helper');
/**
* Class HtmlToolbarHelperTestCase
*
* @since DebugKit 0.1
*/
class HtmlToolbarHelperTestCase extends CakeTestCase {
/**
* Setup Test Case
*/
public static function setupBeforeClass() {
App::build(array(
'View' => array(
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Test' . DS . 'test_app' . DS . 'View' . DS,
APP . 'Plugin' . DS . 'DebugKit' . DS . 'View' . DS,
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'View' . DS
)
), true);
}
/**
* Tear Down Test Case
*/
public static function tearDownAfterClass() {
App::build();
}
/**
* Setup
*
* @return void
*/
public function setUp() {
parent::setUp();
Router::connect('/:controller/:action');
$request = new CakeRequest();
$request->addParams(array('controller' => 'pages', 'action' => 'display'));
$this->Controller = new Controller($request, new CakeResponse());
$this->View = new View($this->Controller);
$this->Toolbar = new ToolbarHelper($this->View, array('output' => 'DebugKit.HtmlToolbar'));
$this->Toolbar->HtmlToolbar = new HtmlToolbarHelper($this->View);
$this->Toolbar->HtmlToolbar->Html = new HtmlHelper($this->View);
$this->Toolbar->HtmlToolbar->Form = new FormHelper($this->View);
}
/**
* Tear Down
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Toolbar, $this->Controller);
}
/**
* Test makeNeatArray with basic types.
*
* @return void
*/
public function testMakeNeatArrayBasic() {
$in = false;
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', '0' , '/strong', '(false)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = null;
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', '0' , '/strong', '(null)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = true;
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', '0' , '/strong', '(true)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array();
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', '0' , '/strong', '(empty)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
}
/**
* Test that cyclic references can be printed.
*
* @return void
*/
public function testMakeNeatArrayCyclicObjects() {
$a = new StdClass;
$b = new StdClass;
$a->child = $b;
$b->parent = $a;
$in = array('obj' => $a);
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
array('ul' => array('class' => 'neat-array depth-0')),
'<li', '<strong', 'obj', '/strong', '(object)',
array('ul' => array('class' => 'neat-array depth-1')),
'<li', '<strong', 'child', '/strong', '(object)',
array('ul' => array('class' => 'neat-array depth-2')),
'<li', '<strong', 'parent', '/strong',
'(object) - recursion',
'/li',
'/ul',
'/li',
'/ul',
'/li',
'/ul'
);
$this->assertTags($result, $expected);
}
/**
* Test Neat Array formatting
*
* @return void
*/
public function testMakeNeatArray() {
$in = array('key' => 'value');
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array('key' => null);
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', 'key', '/strong', '(null)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array('key' => 'value', 'foo' => 'bar');
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'foo', '/strong', 'bar', '/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array(
'key' => 'value',
'foo' => array(
'this' => 'deep',
'another' => 'value'
)
);
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'foo', '/strong',
'(array)',
array('ul' => array('class' => 'neat-array depth-1')),
'<li', '<strong', 'this', '/strong', 'deep', '/li',
'<li', '<strong', 'another', '/strong', 'value', '/li',
'/ul',
'/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array(
'key' => 'value',
'foo' => array(
'this' => 'deep',
'another' => 'value'
),
'lotr' => array(
'gandalf' => 'wizard',
'bilbo' => 'hobbit'
)
);
$result = $this->Toolbar->makeNeatArray($in, 1);
$expected = array(
'ul' => array('class' => 'neat-array depth-0 expanded'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'foo', '/strong',
'(array)',
array('ul' => array('class' => 'neat-array depth-1')),
'<li', '<strong', 'this', '/strong', 'deep', '/li',
'<li', '<strong', 'another', '/strong', 'value', '/li',
'/ul',
'/li',
'<li', '<strong', 'lotr', '/strong',
'(array)',
array('ul' => array('class' => 'neat-array depth-1')),
'<li', '<strong', 'gandalf', '/strong', 'wizard', '/li',
'<li', '<strong', 'bilbo', '/strong', 'hobbit', '/li',
'/ul',
'/li',
'/ul'
);
$this->assertTags($result, $expected);
$result = $this->Toolbar->makeNeatArray($in, 2);
$expected = array(
'ul' => array('class' => 'neat-array depth-0 expanded'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'foo', '/strong',
'(array)',
array('ul' => array('class' => 'neat-array depth-1 expanded')),
'<li', '<strong', 'this', '/strong', 'deep', '/li',
'<li', '<strong', 'another', '/strong', 'value', '/li',
'/ul',
'/li',
'<li', '<strong', 'lotr', '/strong',
'(array)',
array('ul' => array('class' => 'neat-array depth-1 expanded')),
'<li', '<strong', 'gandalf', '/strong', 'wizard', '/li',
'<li', '<strong', 'bilbo', '/strong', 'hobbit', '/li',
'/ul',
'/li',
'/ul'
);
$this->assertTags($result, $expected);
$in = array('key' => 'value', 'array' => array());
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
'ul' => array('class' => 'neat-array depth-0'),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'array', '/strong', '(empty)', '/li',
'/ul'
);
$this->assertTags($result, $expected);
}
/**
* Test makeNeatArray with object inputs.
*
* @return void
*/
public function testMakeNeatArrayObjects() {
$in = new StdClass();
$in->key = 'value';
$in->nested = new StdClass();
$in->nested->name = 'mark';
$result = $this->Toolbar->makeNeatArray($in);
$expected = array(
array('ul' => array('class' => 'neat-array depth-0')),
'<li', '<strong', 'key', '/strong', 'value', '/li',
'<li', '<strong', 'nested', '/strong',
'(object)',
array('ul' => array('class' => 'neat-array depth-1')),
'<li', '<strong', 'name', '/strong', 'mark', '/li',
'/ul',
'/li',
'/ul'
);
$this->assertTags($result, $expected);
}
/**
* Test injection of toolbar
*
* @return void
*/
public function testInjectToolbar() {
$this->Controller->viewPath = 'Posts';
$request = new CakeRequest('/posts/index');
$request->addParams(Router::parse($request->url));
$request->addPaths(array(
'webroot' => '/',
'base' => '/',
'here' => '/posts/index',
));
$this->Controller->setRequest($request);
$this->Controller->helpers = array('Html', 'Js', 'Session', 'DebugKit.Toolbar');
$this->Controller->layout = 'default';
$this->Controller->uses = null;
$this->Controller->components = array('DebugKit.Toolbar');
$this->Controller->constructClasses();
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$result = $this->Controller->render();
$result = str_replace(array("\n", "\r"), '', $result);
$this->assertPattern('#<div id\="debug-kit-toolbar">.+</div>.*</body>#', $result);
}
/**
* test injection of javascript
*
* @return void
*/
public function testJavascriptInjection() {
$this->Controller->viewPath = 'Posts';
$this->Controller->uses = null;
$request = new CakeRequest('/posts/index');
$request->addParams(Router::parse($request->url));
$request->addPaths(array(
'webroot' => '/',
'base' => '/',
'here' => '/posts/index',
));
$this->Controller->setRequest($request);
$this->Controller->helpers = array('Js', 'Html', 'Session');
$this->Controller->components = array('DebugKit.Toolbar');
$this->Controller->layout = 'default';
$this->Controller->constructClasses();
$this->Controller->Components->trigger('startup', array($this->Controller));
$this->Controller->Components->trigger('beforeRender', array($this->Controller));
$result = $this->Controller->render();
$result = str_replace(array("\n", "\r"), '', $result);
$this->assertPattern('#<script\s*type="text/javascript"\s*src="/debug_kit/js/js_debug_toolbar.js(?:\?\d*?)?"\s*>\s?</script>#', $result);
}
/**
* test message creation
*
* @return void
*/
public function testMessage() {
$result = $this->Toolbar->message('test', 'one, two');
$expected = array(
'<p',
'<strong', 'test', '/strong',
' one, two',
'/p',
);
$this->assertTags($result, $expected);
}
/**
* Test Table generation
*
* @return void
*/
public function testTable() {
$rows = array(
array(1,2),
array(3,4),
);
$result = $this->Toolbar->table($rows);
$expected = array(
'table' => array('class' => 'debug-table'),
array('tr' => array('class' => 'odd')),
'<td', '1', '/td',
'<td', '2', '/td',
'/tr',
array('tr' => array('class' => 'even')),
'<td', '3', '/td',
'<td', '4', '/td',
'/tr',
'/table'
);
$this->assertTags($result, $expected);
}
/**
* test starting a panel
*
* @return void
*/
public function testStartPanel() {
$result = $this->Toolbar->panelStart('My Panel', 'my_panel');
$expected = array(
'a' => array('href' => '#my_panel'),
'My Panel',
'/a'
);
$this->assertTags($result, $expected);
}
/**
* test ending a panel
*
* @return void
*/
public function testPanelEnd() {
$result = $this->Toolbar->panelEnd();
$this->assertNull($result);
}
/**
* Test generating links for query explains.
*
* @return void
*/
public function testExplainLink() {
$sql = 'SELECT * FROM tasks';
$result = $this->Toolbar->explainLink($sql, 'default');
$expected = array(
'form' => array('action' => '/debug_kit/toolbar_access/sql_explain', 'method' => 'post',
'accept-charset' => 'utf-8', 'id'),
array('div' => array('style' => 'display:none;')),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
'/div',
array('input' => array('type' => 'hidden', 'id', 'name' => 'data[log][ds]', 'value' => 'default')),
array('input' => array('type' => 'hidden', 'id', 'name' => 'data[log][sql]', 'value' => $sql)),
array('input' => array('type' => 'hidden', 'id', 'name' => 'data[log][hash]', 'value')),
array('input' => array('class' => 'sql-explain-link', 'type' => 'submit', 'value' => 'Explain')),
'/form',
);
$this->assertTags($result, $expected);
}
}

View File

@@ -0,0 +1,179 @@
<?php
/**
* Toolbar facade tests.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('View', 'View');
App::uses('Controller', 'Controller');
App::uses('Helper', 'View');
App::uses('ToolbarHelper', 'DebugKit.View/Helper');
App::uses('ConnectionManager', 'Manager');
/**
* Class MockBackendHelper
*
* @since DebugKit 0.1
*/
class MockBackendHelper extends Helper {
}
/**
* Class ToolbarHelperTestCase
*
*/
class ToolbarHelperTestCase extends CakeTestCase {
/**
* Fixtures
*
* @var array
*/
public $fixtures = array('core.post');
/**
* setUp
*
* @return void
*/
public function setUp() {
parent::setUp();
$db = ConnectionManager::getDatasource('test');
$db->fullDebug = true;
Configure::write('Cache.disable', false);
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::parse('/');
$this->Controller = new Controller(null);
$this->View = new View($this->Controller);
$this->Toolbar = new ToolbarHelper($this->View, array(
'output' => 'MockBackendHelper',
'cacheKey' => 'debug_kit_toolbar_test_case',
'cacheConfig' => 'default'
));
$this->Toolbar->MockBackend = $this->getMock('Helper', array('testMethod'), array($this->View));
$this->_viewPaths = App::path('views');
App::build(array(
'View' => array(
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Test' . DS . 'test_app' . DS . 'View' . DS,
APP . 'Plugin' . DS . 'DebugKit' . DS . 'View' . DS,
CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'View' . DS
)), true);
}
/**
* tearDown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
Cache::delete('debug_kit_toolbar_test_case', 'default');
unset($this->Toolbar, $this->Controller);
}
/**
* test cache writing for views.
*
* @return void
*/
public function testCacheWrite() {
$result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
$this->assertTrue($result);
}
/**
* Ensure that the cache writing only affects the
* top most level of the history stack. As this is where the current request is stored.
*
* @return void
*/
public function testOnlyWritingToFirstElement() {
$values = array(
array('test' => array('content' => array('first', 'values'))),
array('test' => array('content' => array('second', 'values'))),
);
Cache::write('debug_kit_toolbar_test_case', $values, 'default');
$this->Toolbar->writeCache('test', array('new', 'values'));
$result = $this->Toolbar->readCache('test');
$this->assertEquals($result, array('new', 'values'));
$result = $this->Toolbar->readCache('test', 1);
$this->assertEquals($result, array('second', 'values'));
}
/**
* test cache reading for views
*
* @return void
*/
public function testCacheRead() {
$result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
$this->assertTrue($result, 'Cache write failed %s');
$result = $this->Toolbar->readCache('test');
$this->assertEquals($result, array('stuff', 'to', 'cache'), 'Cache value is wrong %s');
$result = $this->Toolbar->writeCache('test', array('new', 'stuff'));
$this->assertTrue($result, 'Cache write failed %s');
$result = $this->Toolbar->readCache('test');
$this->assertEquals($result, array('new', 'stuff'), 'Cache value is wrong %s');
}
/**
* Test that reading/writing doesn't work with no cache config.
*
* @return void
*/
public function testNoCacheConfigPresent() {
$this->Toolbar = new ToolbarHelper($this->View, array('output' => 'MockBackendHelper'));
$result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
$this->assertFalse($result, 'Writing to cache succeeded with no cache config %s');
$result = $this->Toolbar->readCache('test');
$this->assertFalse($result, 'Reading cache succeeded with no cache config %s');
}
/**
* ensure that getQueryLogs works and writes to the cache so the history panel will
* work.
*
* @return void
*/
public function testGetQueryLogs() {
$model = new CakeTestModel(array('table' => 'posts', 'alias' => 'Post'));
$model->find('all');
$model->find('first');
$result = $this->Toolbar->getQueryLogs($model->useDbConfig, array('cache' => false));
$this->assertTrue(is_array($result));
$this->assertTrue(count($result) >= 2, 'Should be more than 2 queries in the log %s');
$this->assertTrue(isset($result['queries'][0]['actions']));
$model->find('first');
Cache::delete('debug_kit_toolbar_test_case', 'default');
$result = $this->Toolbar->getQueryLogs($model->useDbConfig, array('cache' => true));
$cached = $this->Toolbar->readCache('sql_log');
$this->assertTrue(isset($cached[$model->useDbConfig]));
$this->assertEquals($cached[$model->useDbConfig]['queries'][0], $result['queries'][0]);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* DebugKit TestController of test_app
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
/**
* Class DebugKitTestController
*
* @since DebugKit 0.1
*/
class DebugKitTestController extends Controller {
/**
* Mame of the Controller
*
* @var string
*/
public $name = 'DebugKitTest';
/**
* Uses no Models
*
* @var array
*/
public $uses = array();
/**
* Uses only DebugKit Toolbar Component
*
* @var array
*/
public $components = array('DebugKit.Toolbar');
/**
* Return Request Action Value
*
* @return string
*/
public function request_action_return() {
$this->autoRender = false;
return 'I am some value from requestAction.';
}
/**
* Render Request Action
*/
public function request_action_render() {
$this->set('test', 'I have been rendered.');
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Test Panel of test_app
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Class TestPanel
*
* @since DebugKit 0.1
*/
class TestPanel extends DebugPanel {
/**
* Startup
*
* @param Controller $controller
*/
public function startup(Controller $controller) {
$controller->testPanel = true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Test Panel of test_app
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugPanel', 'DebugKit.Lib');
/**
* Class PluginTestPanel
*
*/
class PluginTestPanel extends DebugPanel {
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Request Action Render template
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<?php echo $test; ?>

View File

@@ -0,0 +1 @@
2.2.6

View File

@@ -0,0 +1,59 @@
<?php
/**
* Debug Toolbar Element
*
* Renders all of the other panel elements.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<div id="debug-kit-toolbar">
<?php if (empty($debugToolbarPanels)) :?>
<p class="warning"><?php echo __d('debug_kit', 'There are no active panels. You must enable a panel to see its output.'); ?></p>
<?php else: ?>
<ul id="panel-tabs">
<li class="panel-tab icon">
<a href="#hide" id="hide-toolbar">
<?php echo $this->Html->image('/debug_kit/img/cake.icon.png', array('alt' => 'CakePHP')); ?>
</a>
</li>
<?php foreach ($debugToolbarPanels as $panelName => $panelInfo): ?>
<?php $panelUnderscore = Inflector::underscore($panelName);?>
<li class="panel-tab">
<?php
$title = (empty($panelInfo['title'])) ? Inflector::humanize($panelUnderscore) : $panelInfo['title'];
echo $this->Toolbar->panelStart($title, $panelUnderscore);
?>
<div class="panel-content" id="<?php echo $panelUnderscore ?>-tab">
<a href="#" class="panel-toggle ui-control ui-button">+</a>
<div class="panel-resize-region">
<div class="panel-content-data">
<?php
echo $this->element($panelInfo['elementName'], $panelInfo, array(
'plugin' => (empty($panelInfo['plugin'])) ? null : Inflector::camelize($panelInfo['plugin'])
));
?>
</div>
<div class="panel-content-data panel-history" id="<?php echo $panelUnderscore; ?>-history">
<!-- content here -->
</div>
</div>
<div class="panel-resize-handle ui-control">====</div>
</div>
<?php $this->Toolbar->panelEnd(); ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,84 @@
<?php
/**
* Environment Panel Element
*
* Shows information about the current app environment
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2><?php echo __d('debug_kit', 'App Constants'); ?></h2>
<?php
if (!empty($content['app'])) {
$cakeRows = array();
foreach ($content['app'] as $key => $val) {
$cakeRows[] = array(
$key,
$val
);
}
$headers = array('Constant', 'Value');
echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'Application Environment Vars'));
} else {
echo "No application environment available.";
} ?>
<h2><?php echo __d('debug_kit', 'CakePHP Constants'); ?></h2>
<?php
if (!empty($content['cake'])) {
$cakeRows = array();
foreach ($content['cake'] as $key => $val) {
$cakeRows[] = array(
h($key),
h($val)
);
}
$headers = array('Constant', 'Value');
echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'CakePHP Environment Vars'));
} else {
echo "CakePHP environment unavailable.";
} ?>
<h2><?php echo __d('debug_kit', 'PHP Environment');?></h2>
<?php
$headers = array('Environment Variable', 'Value');
if (!empty($content['php'])) {
$phpRows = array();
foreach ($content['php'] as $key => $val) {
$phpRows[] = array(
h(Inflector::humanize(strtolower($key))),
h($val)
);
}
echo $this->Toolbar->table($phpRows, $headers, array('title' => 'CakePHP Environment Vars'));
} else {
echo "PHP environment unavailable.";
}
if (isset($content['hidef'])) {
echo '<h2>' . __d('debug_kit', 'Hidef Environment') . '</h2>';
if (!empty($content['hidef'])) {
$cakeRows = array();
foreach ($content['hidef'] as $key => $val) {
$cakeRows[] = array(
h($key),
h($val)
);
}
$headers = array('Constant', 'Value');
echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'Hidef Environment Vars'));
} else {
echo "No Hidef environment available.";
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* View Variables Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2> <?php echo __d('debug_kit', 'Request History'); ?></h2>
<?php if (empty($content)): ?>
<p class="warning"><?php echo __d('debug_kit', 'No previous requests logged.'); ?></p>
<?php else: ?>
<?php echo count($content); ?> <?php echo __d('debug_kit', 'previous requests available') ?>
<ul class="history-list">
<li><?php echo $this->Html->link(__d('debug_kit', 'Restore to current request'),
'#', array('class' => 'history-link', 'id' => 'history-restore-current')); ?>
</li>
<?php foreach ($content as $previous): ?>
<li><?php echo $this->Html->link($previous['title'], $previous['url'], array('class' => 'history-link')); ?></li>
<?php endforeach; ?>
</ul>
<?php endif;

View File

@@ -0,0 +1,34 @@
<?php
/**
* Included Files Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 2.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
**/
?>
<h2> <?php echo __d('debug_kit', 'Included Files'); ?></h2>
<h4>Include Paths</h4>
<?php
foreach ($content['paths'] as $i => $path) {
if (strstr($path, CAKE)) {
$content['paths'][$i] = '-> ' . $path;
break;
}
}
echo $this->Toolbar->makeNeatArray(array_filter($content['paths']));
unset($content['paths']);
?>
<h4>Included Files</h4>
<?php echo $this->Toolbar->makeNeatArray($content);

View File

@@ -0,0 +1,41 @@
<?php
/**
* Log Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2><?php echo __d('debug_kit', 'Logs') ?></h2>
<div class="code-table">
<?php if ($content instanceof DebugKitLog): ?>
<?php foreach ($content->logs as $logName => $logs): ?>
<h3><?php echo $logName ?></h3>
<?php
$len = count($logs);
if ($len > 0):
$headers = array(__d('debug_kit', 'Time'), __d('debug_kit', 'Message'));
$rows = array();
for ($i = 0; $i < $len; $i++):
$rows[] = array(
$logs[$i][0], h($logs[$i][1])
);
endfor;
echo $this->Toolbar->table($rows, $headers, array('title' => $logName));
endif; ?>
<?php endforeach; ?>
<?php if (empty($content->logs)): ?>
<p class="info"><?php echo __d('debug_kit', 'There were no log entries made this request'); ?></p>
<?php endif; ?>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,50 @@
<?php
/**
* Request Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2> <?php echo __d('debug_kit', 'Request'); ?></h2>
<h4>Cake Params</h4>
<?php echo $this->Toolbar->makeNeatArray($content['params']); ?>
<h4>Post data</h4>
<?php
if (empty($content['data'])):
echo '<p class="info">' . __d('debug_kit', 'No post data.') . '</p>';
else:
echo $this->Toolbar->makeNeatArray($content['data']);
endif;
?>
<h4>Query string</h4>
<?php
if (empty($content['query'])):
echo '<p class="info">' . __d('debug_kit', 'No querystring data.') . '</p>';
else:
echo $this->Toolbar->makeNeatArray($content['query']);
endif;
?>
<h4>Cookie</h4>
<?php if (isset($content['cookie'])): ?>
<?php echo $this->Toolbar->makeNeatArray($content['cookie']); ?>
<?php else: ?>
<p class="info">To view Cookies, add CookieComponent to Controller</p>
<?php endif; ?>
<h4><?php echo __d('debug_kit', 'Current Route') ?></h4>
<?php echo $this->Toolbar->makeNeatArray($content['currentRoute']);

View File

@@ -0,0 +1,20 @@
<?php
/**
* Session Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2><?php echo __d('debug_kit', 'Session'); ?></h2>
<?php echo $this->Toolbar->makeNeatArray($content);

View File

@@ -0,0 +1,80 @@
<?php
/**
* SQL Log Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
$headers = array('Query', 'Affected', 'Num. rows', 'Took (ms)', 'Actions');
if (isset($debugKitInHistoryMode)) {
$content = $this->Toolbar->readCache('sql_log', $this->request->params['pass'][0]);
}
?>
<h2><?php echo __d('debug_kit', 'Sql Logs')?></h2>
<?php if (!empty($content)) : ?>
<?php foreach ($content['connections'] as $dbName => $explain): ?>
<div class="sql-log-panel-query-log">
<h4><?php echo $dbName ?></h4>
<?php
if (!isset($debugKitInHistoryMode)):
$queryLog = $this->Toolbar->getQueryLogs($dbName, array(
'explain' => $explain, 'threshold' => $content['threshold']
));
else:
$queryLog = $content[$dbName];
endif;
if (empty($queryLog['queries'])):
if (Configure::read('debug') < 2):
echo ' ' . __d('debug_kit', 'No query logs when debug < 2.');
else:
echo ' ' . __d('debug_kit', 'No query logs.');
endif;
else:
$hashes = array();
$duplicate = 0;
foreach ($queryLog['queries'] as $key => $val) {
$hash = sha1($val['query']);
if (!isset($hashes[$hash]) || $hashes[$hash] !== $val['affected']) {
$hashes[$hash] = $val['affected'];
continue;
}
$duplicate++;
$queryLog['queries'][$key]['query'] = '<span class="alert-duplicate">' . $val['query'] . '</span>';
}
echo '<h5>';
echo __d(
'debug_kit',
'Total Time: %s ms <br />Total Queries: %s queries',
$queryLog['time'],
$queryLog['count']
);
echo '</h5>';
echo $this->Toolbar->table($queryLog['queries'], $headers, array('title' => 'SQL Log ' . $dbName));
if ($duplicate) {
echo '<p class="alert alert-warning">' . __d('debug_kit', '%s duplicate queries run.', $duplicate) . '</p>';
}
?>
<h4><?php echo __d('debug_kit', 'Query Explain:'); ?></h4>
<div id="sql-log-explain-<?php echo $dbName ?>">
<a id="debug-kit-explain-<?php echo $dbName ?>"> </a>
<p><?php echo __d('debug_kit', 'Click an "Explain" link above, to see the query explanation.'); ?></p>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php else:
echo $this->Toolbar->message('Warning', __d('debug_kit', 'No active database connections'));
endif;

View File

@@ -0,0 +1,110 @@
<?php
/**
* Timer Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
$this->Number = $this->Helpers->load('Number');
$this->SimpleGraph = $this->Helpers->load('DebugKit.SimpleGraph');
if (!isset($debugKitInHistoryMode)):
$timers = DebugTimer::getAll(true);
$currentMemory = DebugKitDebugger::getMemoryUse();
$peakMemory = DebugKitDebugger::getPeakMemoryUse();
$requestTime = DebugTimer::requestTime();
else:
$content = $this->Toolbar->readCache('timer', $this->request->params['pass'][0]);
if (is_array($content)):
extract($content);
endif;
endif;
?>
<div class="debug-info">
<h2><?php echo __d('debug_kit', 'Memory'); ?></h2>
<div class="peak-mem-use">
<?php
echo $this->Toolbar->message(__d('debug_kit', 'Peak Memory Use'), $this->Number->toReadableSize($peakMemory)); ?>
</div>
<?php
$headers = array(__d('debug_kit', 'Message'), __d('debug_kit', 'Memory use'));
$memoryPoints = DebugKitDebugger::getMemoryPoints();
$rows = array();
foreach ($memoryPoints as $key => $value):
$rows[] = array($key, $this->Number->toReadableSize($value));
endforeach;
echo $this->Toolbar->table($rows, $headers);
?>
</div>
<div class="debug-info debug-timers">
<h2><?php echo __d('debug_kit', 'Timers'); ?></h2>
<div class="request-time">
<?php $totalTime = __d('debug_kit', '%s (ms)', $this->Number->precision($requestTime * 1000, 0)); ?>
<?php echo $this->Toolbar->message(__d('debug_kit', 'Total Request Time:'), $totalTime)?>
</div>
<?php
$rows = array();
$end = end($timers);
$maxTime = $end['end'];
$headers = array(
__d('debug_kit', 'Message'),
__d('debug_kit', 'Time in ms'),
__d('debug_kit', 'Graph')
);
$i = 0;
$values = array_values($timers);
foreach ($timers as $timerName => $timeInfo):
$indent = 0;
for ($j = 0; $j < $i; $j++) {
if (($values[$j]['end'] > $timeInfo['start']) && ($values[$j]['end']) > ($timeInfo['end'])) {
$indent++;
}
}
$indent = str_repeat(' &raquo; ', $indent);
$rows[] = array(
$indent . $timeInfo['message'],
$this->Number->precision($timeInfo['time'] * 1000, 2),
$this->SimpleGraph->bar(
$this->Number->precision($timeInfo['time'] * 1000, 2),
$this->Number->precision($timeInfo['start'] * 1000, 2),
array(
'max' => $maxTime * 1000,
'requestTime' => $requestTime * 1000,
)
)
);
$i++;
endforeach;
if (strtolower($this->Toolbar->getName()) === 'firephptoolbar'):
for ($i = 0, $len = count($rows); $i < $len; $i++):
unset($rows[$i][2]);
endfor;
unset($headers[2]);
endif;
echo $this->Toolbar->table($rows, $headers, array('title' => 'Timers'));
if (!isset($debugKitInHistoryMode)):
$this->Toolbar->writeCache('timer', compact('timers', 'currentMemory', 'peakMemory', 'requestTime'));
endif;
?>
</div>

View File

@@ -0,0 +1,23 @@
<?php
/**
* View Variables Panel Element
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2> <?php echo __d('debug_kit', 'View Variables'); ?></h2>
<?php
$content['$this->validationErrors'] = $this->validationErrors;
$content['Loaded Helpers'] = $this->Helpers->attached();
echo $this->Toolbar->makeNeatArray($content);

View File

@@ -0,0 +1,90 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugTimer', 'DebugKit.Lib');
App::uses('DebugMemory', 'DebugKit.Lib');
App::uses('Helper', 'View');
/**
* Class DebugTimerHelper
*
* Tracks time and memory usage while rendering view.
*
*/
class DebugTimerHelper extends Helper {
/**
* Set to true when rendering is complete.
* Used to not add timers for rendering the toolbar.
*
* @var boolean
*/
protected $_renderComplete = false;
/**
* Constructor
*
* @param View $View
* @param array $settings
*/
public function __construct(View $View, $settings = array()) {
parent::__construct($View, $settings);
DebugTimer::start(
'viewRender',
__d('debug_kit', 'Rendering View')
);
}
/**
* Sets a timer point before rendering a file.
*
* @param string $viewFile The view being rendered
*/
public function beforeRenderFile($viewFile) {
if ($this->_renderComplete) {
return;
}
DebugTimer::start(
'render_' . basename($viewFile),
__d('debug_kit', 'Rendering %s',
Debugger::trimPath($viewFile))
);
}
/**
* Stops the timer point before rendering a file.
*
* @param string $viewFile The view being rendered
* @param string $content The contents of the view.
*/
public function afterRenderFile($viewFile, $content) {
if ($this->_renderComplete) {
return;
}
DebugTimer::stop('render_' . basename($viewFile));
}
/**
* Stop timers for rendering.
*
* @param string $layoutFile
*/
public function afterLayout($layoutFile) {
DebugTimer::stop('viewRender');
DebugTimer::stop('controllerRender');
DebugMemory::record(__d('debug_kit', 'View render complete'));
$this->_renderComplete = true;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('ToolbarHelper', 'DebugKit.View/Helper');
App::uses('FireCake', 'DebugKit.Lib');
/**
* FirePHP Toolbar Helper
*
* Injects the toolbar elements into non-HTML layouts via FireCake.
*
*/
class FirePhpToolbarHelper extends ToolbarHelper {
/**
* settings property
*
* @var array
*/
public $settings = array('format' => 'firePHP', 'forceEnable' => false);
/**
* send method
*
* @return void
*/
public function send() {
$view = $this->_View;
$view->element('debug_toolbar', array('disableTimer' => true), array('plugin' => 'DebugKit'));
}
/**
* makeNeatArray.
*
* wraps FireCake::dump() allowing panel elements to continue functioning
*
* @param string $values
* @return void
*/
public function makeNeatArray($values) {
FireCake::info($values);
}
/**
* Create a simple message
*
* @param string $label Label of message
* @param string $message Message content
* @return void
*/
public function message($label, $message) {
FireCake::log($message, $label);
}
/**
* Generate a table with FireCake
*
* @param array $rows Rows to print
* @param array $headers Headers for table
* @param array $options Additional options and params
* @return void
*/
public function table($rows, $headers, $options = array()) {
$title = $headers[0];
if (isset($options['title'])) {
$title = $options['title'];
}
foreach ($rows as $i => $row) {
$rows[$i] = array_values($row);
}
array_unshift($rows, $headers);
FireCake::table($title, $rows);
}
/**
* Start a panel which is a 'Group' in FirePHP
*
* @param $title
* @param $anchor
* @return void
*/
public function panelStart($title, $anchor) {
FireCake::group($title);
}
/**
* End a panel (Group)
*
* @return void
*/
public function panelEnd() {
FireCake::groupEnd();
}
}

View File

@@ -0,0 +1,238 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('ToolbarHelper', 'DebugKit.View/Helper');
App::uses('Security', 'Utility');
/**
* Html Toolbar Helper
*
* Injects the toolbar elements into HTML layouts.
* Contains helper methods for
*
* @since DebugKit 0.1
*/
class HtmlToolbarHelper extends ToolbarHelper {
/**
* helpers property
*
* @var array
*/
public $helpers = array('Html', 'Form');
/**
* settings property
*
* @var array
*/
public $settings = array('format' => 'html', 'forceEnable' => false);
/**
* Recursively goes through an array and makes neat HTML out of it.
*
* @param mixed $values Array to make pretty.
* @param integer $openDepth Depth to add open class
* @param integer $currentDepth current depth.
* @param boolean $doubleEncode
* @return string
*/
public function makeNeatArray($values, $openDepth = 0, $currentDepth = 0, $doubleEncode = false) {
static $printedObjects = null;
if ($currentDepth === 0) {
$printedObjects = new SplObjectStorage();
}
$className = "neat-array depth-$currentDepth";
if ($openDepth > $currentDepth) {
$className .= ' expanded';
}
$nextDepth = $currentDepth + 1;
$out = "<ul class=\"$className\">";
if (!is_array($values)) {
if (is_bool($values)) {
$values = array($values);
}
if ($values === null) {
$values = array(null);
}
}
if (empty($values)) {
$values[] = '(empty)';
}
foreach ($values as $key => $value) {
$out .= '<li><strong>' . h($key, $doubleEncode) . '</strong>';
if (is_array($value) && count($value) > 0) {
$out .= '(array)';
} elseif (is_object($value)) {
$out .= '(object)';
}
if ($value === null) {
$value = '(null)';
}
if ($value === false) {
$value = '(false)';
}
if ($value === true) {
$value = '(true)';
}
if (empty($value) && $value != 0) {
$value = '(empty)';
}
if ($value instanceof Closure) {
$value = 'function';
}
$isObject = is_object($value);
if ($isObject && $printedObjects->contains($value)) {
$isObject = false;
$value = ' - recursion';
}
if ($isObject) {
$printedObjects->attach($value);
}
if (
(
$value instanceof ArrayAccess ||
$value instanceof Iterator ||
is_array($value) ||
$isObject
) && !empty($value)
) {
$out .= $this->makeNeatArray($value, $openDepth, $nextDepth, $doubleEncode);
} else {
$out .= h($value, $doubleEncode);
}
$out .= '</li>';
}
$out .= '</ul>';
return $out;
}
/**
* Create an HTML message
*
* @param string $label label content
* @param string $message message content
* @return string
*/
public function message($label, $message) {
return sprintf('<p><strong>%s</strong> %s</p>', $label, $message);
}
/**
* Start a panel.
* Make a link and anchor.
*
* @param $title
* @param $anchor
* @return string
*/
public function panelStart($title, $anchor) {
$link = $this->Html->link($title, '#' . $anchor);
return $link;
}
/**
* Create a table.
*
* @param array $rows Rows to make.
* @param array $headers Optional header row.
* @return string
*/
public function table($rows, $headers = array()) {
$out = '<table class="debug-table">';
if (!empty($headers)) {
$out .= $this->Html->tableHeaders($headers);
}
$out .= $this->Html->tableCells($rows, array('class' => 'odd'), array('class' => 'even'), false, false);
$out .= '</table>';
return $out;
}
/**
* Send method
*
* @return void
*/
public function send() {
if (!$this->settings['forceEnable'] && Configure::read('debug') == 0) {
return;
}
$view = $this->_View;
$head = '';
if (isset($view->viewVars['debugToolbarCss']) && !empty($view->viewVars['debugToolbarCss'])) {
$head .= $this->Html->css($view->viewVars['debugToolbarCss']);
}
$js = sprintf('window.DEBUGKIT_JQUERY_URL = "%s";', $this->webroot('/debug_kit/js/jquery.js'));
$head .= $this->Html->scriptBlock($js);
if (isset($view->viewVars['debugToolbarJavascript'])) {
foreach ($view->viewVars['debugToolbarJavascript'] as $script) {
if ($script) {
$head .= $this->Html->script($script);
}
}
}
$search = '</head>';
$pos = strpos($view->output, $search);
if ($pos !== false) {
$view->output = substr_replace($view->output, $head . "\n</head>", $pos, strlen($search));
}
$toolbar = $view->element('debug_toolbar', array('disableTimer' => true), array('plugin' => 'DebugKit'));
$search = '</body>';
$pos = strrpos($view->output, $search);
if ($pos !== false) {
$view->output = substr_replace($view->output, $toolbar . "\n</body>", $pos, strlen($search));
}
}
/**
* Generates a SQL explain link for a given query
*
* @param string $sql SQL query string you want an explain link for.
* @param $connection
* @return string Rendered Html link or '' if the query is not a select/describe
*/
public function explainLink($sql, $connection) {
if (!preg_match('/^[\s()]*SELECT/i', $sql)) {
return '';
}
$sql = str_replace(array("\n", "\t"), ' ', $sql);
$hash = Security::hash($sql . $connection, 'sha1', true);
$url = array(
'plugin' => 'debug_kit',
'controller' => 'toolbar_access',
'action' => 'sql_explain'
);
foreach (Router::prefixes() as $prefix) {
$url[$prefix] = false;
}
$this->explainLinkUid = (isset($this->explainLinkUid) ? $this->explainLinkUid + 1 : 0);
$uid = $this->explainLinkUid . '_' . rand(0, 10000);
$form = $this->Form->create('log', array('url' => $url, 'id' => "logForm{$uid}"));
$form .= $this->Form->hidden('log.ds', array('id' => "logDs{$uid}", 'value' => $connection));
$form .= $this->Form->hidden('log.sql', array('id' => "logSql{$uid}", 'value' => $sql));
$form .= $this->Form->hidden('log.hash', array('id' => "logHash{$uid}", 'value' => $hash));
$form .= $this->Form->submit(__d('debug_kit', 'Explain'), array(
'div' => false,
'class' => 'sql-explain-link'
));
$form .= $this->Form->end();
return $form;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AppHelper', 'View/Helper');
App::uses('HtmlHelper', 'View/Helper');
/**
* Class SimpleGraphHelper
*
* Allows creation and display of extremely simple graphing elements
*
* @since DebugKit 1.0
*/
class SimpleGraphHelper extends AppHelper {
/**
* Helpers
*
* @var array
*/
public $helpers = array('Html');
/**
* Default settings to be applied to each Simple Graph
*
* Allowed options:
*
* - max => (int) Maximum value in the graphs
* - width => (int)
* - valueType => string (value, percentage)
* - style => array
*
* @var array
*/
protected $_defaultSettings = array(
'max' => 100,
'width' => 350,
'valueType' => 'value',
);
/**
* bar method
*
* @param $value Value to be graphed
* @param $offset how much indentation
* @param array|\Graph $options Graph options
* @return string Html graph
*/
public function bar($value, $offset, $options = array()) {
$settings = array_merge($this->_defaultSettings, $options);
extract($settings);
$graphValue = ($value / $max) * $width;
$graphValue = max(round($graphValue), 1);
if ($valueType === 'percentage') {
$graphOffset = 0;
} else {
$graphOffset = ($offset / $max) * $width;
$graphOffset = round($graphOffset);
}
return $this->Html->div(
'debug-kit-graph-bar',
$this->Html->div(
'debug-kit-graph-bar-value',
' ',
array(
'style' => "margin-left: {$graphOffset}px; width: {$graphValue}px",
'title' => __d('debug_kit', "Starting %sms into the request, taking %sms", $offset, $value),
)
),
array('style' => "width: {$width}px;"),
false
);
}
}

View File

@@ -0,0 +1,171 @@
<?php
/**
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since v 1.0 (22-Jun-2009)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('File', 'Utility');
/**
* TidyHelper class
*
* Passes html through tidy on the command line, and reports markup errors
*
* @uses AppHelper
* @since v 1.0 (22-Jun-2009)
*/
class TidyHelper extends AppHelper {
/**
* helpers property
*
* @var array
*/
public $helpers = array('DebugKit.Toolbar');
/**
* results property
*
* @var mixed null
*/
public $results = null;
/**
* Return a nested array of errors for the passed html string
* Fudge the markup slightly so that the tag which is invalid is highlighted
*
* @param string $html ''
* @param string $out ''
* @return array
*/
public function process($html = '', &$out = '') {
$errors = $this->tidyErrors($html, $out);
if (!$errors) {
return array();
}
$result = array('Error' => array(), 'Warning' => array(), 'Misc' => array());
$errors = explode("\n", $errors);
$markup = explode("\n", $out);
foreach ($errors as $error) {
preg_match('@line (\d+) column (\d+) - (\w+): (.*)@', $error, $matches);
if ($matches) {
list($original, $line, $column, $type, $message) = $matches;
$line = $line - 1;
$string = '</strong>';
if (isset($markup[$line - 1])) {
$string .= h($markup[$line - 1]);
}
$string .= '<strong>' . h(@$markup[$line]) . '</strong>';
if (isset($markup[$line + 1])) {
$string .= h($markup[$line + 1]);
}
$string .= '</strong>';
$result[$type][$string][] = h($message);
} elseif ($error) {
$message = $error;
$result['Misc'][h($message)][] = h($message);
}
}
$this->results = $result;
return $result;
}
/**
* report method
*
* Call process if a string is passed, or no prior results exist - and return the results using
* the toolbar helper to generate a nested navigatable array
*
* @param mixed $html null
* @return string
*/
public function report($html = null) {
if ($html) {
$this->process($html);
} elseif ($this->results === null) {
$this->process($this->_View->output);
}
if (!$this->results) {
return '<p>' . __d('debug_kit', 'No markup errors found') . '</p>';
}
foreach ($this->results as &$results) {
foreach ($results as $type => &$messages) {
foreach ($messages as &$message) {
$message = html_entity_decode($message, ENT_COMPAT, Configure::read('App.encoding'));
}
}
}
return $this->Toolbar->makeNeatArray(array_filter($this->results), 0, 0, false);
}
/**
* Run the html string through tidy, and return the (raw) errors. pass back a reference to the
* normalized string so that the error messages can be linked to the line that caused them.
*
* @param string $in ''
* @param string $out ''
* @return string
*/
public function tidyErrors($in = '', &$out = '') {
$out = preg_replace('@>\s*<@s', ">\n<", $in);
// direct access? windows etc
if (function_exists('tidy_parse_string')) {
$tidy = tidy_parse_string($out, array(), 'UTF8');
$tidy->cleanRepair();
$errors = $tidy->errorBuffer . "\n";
return $errors;
}
// cli
$File = new File(rtrim(TMP, DS) . DS . rand() . '.html', true);
$File->write($out);
$path = $File->pwd();
$errors = $path . '.err';
$this->_exec("tidy -eq -utf8 -f $errors $path");
$File->delete();
if (!file_exists($errors)) {
return '';
}
$Error = new File($errors);
$errors = $Error->read();
$Error->delete();
return $errors;
}
/**
* exec method
*
* @param mixed $cmd
* @param mixed $out null
* @return boolean True if successful
*/
protected function _exec($cmd, &$out = null) {
if (DS === '/') {
$_out = exec($cmd . ' 2>&1', $out, $return);
} else {
$_out = exec($cmd, $out, $return);
}
if (Configure::read('debug')) {
$source = Debugger::trace(array('depth' => 1, 'start' => 2)) . "\n";
//CakeLog::write('system_calls_' . date('Y-m-d'), "\n" . $source . Debugger::exportVar(compact('cmd','out','return')));
//CakeLog::write('system_calls', "\n" . $source . Debugger::exportVar(compact('cmd','out','return')));
}
if ($return) {
return false;
}
return $_out ? $_out : true;
}
}

View File

@@ -0,0 +1,226 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('DebugKitDebugger', 'DebugKit.Lib');
App::uses('AppHelper', 'View/Helper');
App::uses('ConnectionManager', 'Model');
/**
* Provides Base methods for content specific debug toolbar helpers.
* Acts as a facade for other toolbars helpers as well.
*
* @since DebugKit 0.1
*/
class ToolbarHelper extends AppHelper {
/**
* settings property to be overloaded. Subclasses should specify a format
*
* @var array
*/
public $settings = array();
/**
* flag for whether or not cache is enabled.
*
* @var boolean
*/
protected $_cacheEnabled = false;
/**
* Construct the helper and make the backend helper.
*
* @param $View
* @param array|string $options
* @return \ToolbarHelper
*/
public function __construct($View, $options = array()) {
$this->_myName = strtolower(get_class($this));
$this->settings = array_merge($this->settings, $options);
if ($this->_myName !== 'toolbarhelper') {
parent::__construct($View, $options);
return;
}
if (!isset($options['output'])) {
$options['output'] = 'DebugKit.HtmlToolbar';
}
$className = $options['output'];
if (strpos($options['output'], '.') !== false) {
list($plugin, $className) = explode('.', $options['output']);
}
$this->_backEndClassName = $className;
$this->helpers[$options['output']] = $options;
if (isset($options['cacheKey']) && isset($options['cacheConfig'])) {
$this->_cacheKey = $options['cacheKey'];
$this->_cacheConfig = $options['cacheConfig'];
$this->_cacheEnabled = true;
}
parent::__construct($View, $options);
}
/**
* afterLayout callback
*
* @param string $layoutFile
* @return void
*/
public function afterLayout($layoutFile) {
if (!$this->request->is('requested')) {
$this->send();
}
}
/**
* Get the name of the backend Helper
* used to conditionally trigger toolbar output
*
* @return string
*/
public function getName() {
return $this->_backEndClassName;
}
/**
* call__
*
* Allows method calls on backend helper
*
* @param string $method
* @param mixed $params
* @return mixed|void
*/
public function __call($method, $params) {
if (method_exists($this->{$this->_backEndClassName}, $method)) {
return $this->{$this->_backEndClassName}->dispatchMethod($method, $params);
}
}
/**
* Allows for writing to panel cache from view.
* Some panels generate all variables in the view by
* necessity ie. Timer. Using this method, will allow you to replace in full
* the content for a panel.
*
* @param string $name Name of the panel you are replacing.
* @param string $content Content to write to the panel.
* @return boolean Success of write.
*/
public function writeCache($name, $content) {
if (!$this->_cacheEnabled) {
return false;
}
$existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
$existing[0][$name]['content'] = $content;
return Cache::write($this->_cacheKey, $existing, $this->_cacheConfig);
}
/**
* Read the toolbar
*
* @param string $name Name of the panel you want cached data for
* @param integer $index
* @return mixed Boolean false on failure, array of data otherwise.
*/
public function readCache($name, $index = 0) {
if (!$this->_cacheEnabled) {
return false;
}
$existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
if (!isset($existing[$index][$name]['content'])) {
return false;
}
return $existing[$index][$name]['content'];
}
/**
* Gets the query logs for the given connection names.
*
* ### Options
*
* - explain - Whether explain links should be generated for this connection.
* - cache - Whether the toolbar_state Cache should be updated.
* - threshold - The threshold at which a visual 'maybe slow' flag should be added.
* results with rows/ms lower than $threshold will be marked.
*
* @param string $connection Connection name to get logs for.
* @param array $options Options for the query log retrieval.
* @return array Array of data to be converted into a table.
*/
public function getQueryLogs($connection, $options = array()) {
$options += array('explain' => false, 'cache' => true, 'threshold' => 20);
$db = ConnectionManager::getDataSource($connection);
if (!method_exists($db, 'getLog')) {
return array();
}
$log = $db->getLog();
$out = array(
'queries' => array(),
'count' => $log['count'],
'time' => $log['time']
);
foreach ($log['log'] as $i => $query) {
$query += array('query' => null);
$isSlow = (
$query['took'] > 0 &&
$query['numRows'] / $query['took'] != 1 &&
$query['numRows'] / $query['took'] <= $options['threshold']
);
$query['actions'] = '';
$isHtml = ($this->getName() === 'HtmlToolbar');
if ($isSlow && $isHtml) {
$query['actions'] = sprintf(
'<span class="slow-query">%s</span>',
__d('debug_kit', 'maybe slow')
);
} elseif ($isSlow) {
$query['actions'] = '*';
}
if ($options['explain'] && $isHtml) {
$query['actions'] .= $this->explainLink($query['query'], $connection);
}
if ($isHtml) {
$query['query'] = h($query['query']);
if (!empty($query['params']) && is_array($query['params'])) {
$bindParam = $bindType = null;
if (preg_match('/.+ :.+/', $query['query'])) {
$bindType = true;
}
foreach ($query['params'] as $bindKey => $bindVal) {
if ($bindType === true) {
$bindParam .= h($bindKey) . " => " . h($bindVal) . ", ";
} else {
$bindParam .= h($bindVal) . ", ";
}
}
$query['query'] .= " [ " . rtrim($bindParam, ', ') . " ]";
}
}
unset($query['params']);
$out['queries'][] = $query;
}
if ($options['cache']) {
$existing = $this->readCache('sql_log');
$existing[$connection] = $out;
$this->writeCache('sql_log', $existing);
}
return $out;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Toolbar history state view.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
$panels = array();
foreach ($toolbarState as $panelName => $panel) {
if (!empty($panel) && !empty($panel['elementName'])) {
$panels[$panelName] = $this->element($panel['elementName'], array(
'content' => $panel['content']
), array(
'plugin' => Inflector::camelize($panel['plugin'])
));
}
}
echo json_encode($panels);
Configure::write('debug', 0);

View File

@@ -0,0 +1,11 @@
<table class="sql-log-query-explain debug-table">
<?php
$headers = array_shift($result);
echo $this->Html->tableHeaders($headers);
echo $this->Html->tableCells($result);
?>
</table>
<?php
// Consume and toss out the timers
$timers = DebugKitDebugger::getTimers(true);

View File

@@ -0,0 +1,35 @@
{
"name": "cakephp/debug_kit",
"description": "CakePHP Debug Kit",
"type": "cakephp-plugin",
"keywords": ["cakephp", "debug", "kit"],
"homepage": "https://github.com/cakephp/debug_kit",
"license": "MIT",
"authors": [
{
"name": "Mark Story",
"homepage": "http://mark-story.com",
"role": "Author"
},
{
"name": "CakePHP Community",
"homepage": "https://github.com/cakephp/debug_kit/graphs/contributors"
}
],
"support": {
"issues": "https://github.com/cakephp/debug_kit/issues",
"forum": "http://stackoverflow.com/tags/cakephp",
"irc": "irc://irc.freenode.org/cakephp",
"source": "https://github.com/cakephp/debug_kit"
},
"require": {
"php": ">=5.3.0",
"composer/installers": "*"
},
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
},
"installer-name": "DebugKit"
}
}

View File

@@ -0,0 +1,382 @@
/* @override http://localhost/mark_story/site/debug_kit/css/debug_toolbar.css */
#debug-kit-toolbar {
position: fixed;
top: 0;
right:0px;
width: 100%;
height: 1%;
overflow: visible;
z-index:10000;
font-family: helvetica, arial, sans-serif;
font-size: 12px;
direction: ltr;
}
#debug-kit-toolbar img {
border:0;
outline:0;
}
/* panel tabs */
#debug-kit-toolbar #panel-tabs {
float: right;
list-style: none;
margin: 0;
padding: 0;
box-shadow: 0 5px 6px rgba(0, 0, 0, 0.5);
border-radius: 8px 0 0 8px;
}
#debug-kit-toolbar .panel-tab {
clear: none;
float: left;
margin: 0;
padding: 0;
list-style: none;
}
#debug-kit-toolbar .panel-tab > a {
float: left;
clear: none;
background: #efefef;
background: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#cacaca));
background: -moz-linear-gradient(top, #efefef, #cacaca);
color: #222;
padding: 6px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #aaa;
font-size: 12px;
line-height: 16px;
margin: 0;
display: block;
text-decoration:none;
text-shadow:1px 1px #eee;
-moz-text-shadow:1px 1px #eee;
-webkit-text-shadow:1px 1px #eee;
}
#debug-kit-toolbar .panel-tab .active {
background: #fff;
background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff));
background: -moz-linear-gradient(top, #f5f5f5, #fff);
}
#debug-kit-toolbar .panel-tab > a:hover {
background: #fff;
background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff));
background: -moz-linear-gradient(top, #f5f5f5, #fff);
text-decoration:underline;
}
#debug-kit-toolbar .panel-tab.icon a {
padding: 4px;
}
#debug-kit-toolbar .panel-tab a.edit-value {
float: none;
display: inline;
}
#debug-kit-toolbar .panel-tab.icon a {
border-radius: 8px 0 0 8px;
}
#debug-kit-toolbar .panel-tab.icon img {
display:block;
}
/* panel content */
#debug-kit-toolbar .panel-content {
position: absolute;
text-align: left;
width: auto;
top:28px;
right:0px;
background: #fff;
color: #000;
width:100%;
box-shadow:0px 5px 6px rgba(0, 0, 0, 0.5);
height: 200px;
overflow: hidden;
}
#debug-kit-toolbar .panel-resize-region {
padding:15px;
position: absolute;
top: 0;
bottom: 14px;
left: 0;
right: 0;
overflow: auto;
}
#debug-kit-toolbar .ui-control {
background:#ccc;
background: -webkit-gradient(linear, left top, left bottom, from(#d6d6d6), to(#c2c2c2));
background: -moz-linear-gradient(top, #d6d6d6, #c2c2c2);
text-align:center;
border-top:1px solid #afafaf;
border-bottom:1px solid #7c7c7c;
color:#666;
text-shadow: 1px 1px #eee;
-webkit-text-shadow: 1px 1px #eee;
-moz-text-shadow: 1px 1px #eee;
}
#debug-kit-toolbar .ui-button {
border-radius: 5px;
}
#debug-kit-toolbar .ui-button:hover {
text-decoration: none;
background:#ccc;
background: -webkit-gradient(linear, left top, left bottom, from(#c2c2c2), to(#d6d6d6));
background: -moz-linear-gradient(top, #c2c2c2, #d6d6d6);
}
#debug-kit-toolbar .panel-resize-handle {
cursor: row-resize;
height:14px;
line-height: 14px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
#debug-kit-toolbar .panel-toggle {
float: right;
display: block;
width: 16px;
height: 16px;
font-size: 16px;
line-height: 14px;
border-left: 1px solid #afafaf;
border-right: 1px solid #7c7c7c;
text-decoration: none;
margin: 10px 20px 0 0;
z-index: 999;
position: relative;
}
/* Hide panel content by default */
#debug-kit-toolbar .panel-content {
display: none;
}
#debug-kit-toolbar .panel-content p {
margin: 1em 0;
}
#debug-kit-toolbar .panel-content h2 {
padding: 0;
margin-top:0;
}
#debug-kit-toolbar .panel-content h3 {
padding: 0;
margin-top: 1em;
}
#debug-kit-toolbar .panel-content .info {
padding: 4px;
border-top: 1px dashed #6c6cff;
border-bottom: 1px dashed #6c6cff;
}
#debug-kit-toolbar h1,
#debug-kit-toolbar h2,
#debug-kit-toolbar h3,
#debug-kit-toolbar h4,
#debug-kit-toolbar h5,
#debug-kit-toolbar th {
color: #5d1717;
font-family: Arial, sans-serif;
margin-bottom:0.6em;
background:none;
}
#debug-kit-toolbar h1 {
font-size: 18px;
}
#debug-kit-toolbar h2 {
font-size: 16px;
}
#debug-kit-toolbar h4 {
font-size: 14px;
}
/* panel tables */
#debug-kit-toolbar .debug-table {
width: 100%;
border: 1px solid #eee;
border-left: 0;
clear:both;
margin-bottom: 20px;
border-spacing: 0;
}
#debug-kit-toolbar .debug-table td,
#debug-kit-toolbar .debug-table th {
text-align: left;
border: 0;
border-left: 1px solid #eee;
padding: 3px;
margin: 0;
}
#debug-kit-toolbar table.debug-table th {
border-bottom: 1px solid #bbb;
border-left: 1px solid #bbb;
background: -webkit-linear-gradient(top, #d4d4d4, #c1c1c1);
background: -moz-linear-gradient(top, #d4d4d4, #c1c1c1);
color: #222;
font-weight: bold;
line-height: 16px;
}
#debug-kit-toolbar .debug-table tr:nth-child(2n) td {
background: #f6f6f6;
}
#debug-kit-toolbar .debug-timers .debug-table td:nth-child(2),
#debug-kit-toolbar .debug-timers .debug-table th:nth-child(2) {
text-align:right;
}
/** code tables **/
#debug-kit-toolbar .code-table td {
white-space: pre;
font-family: monaco, Consolas, "courier new", courier, monospaced;
}
#debug-kit-toolbar .code-table td:first-child {
width: 15%;
}
#debug-kit-toolbar .code-table td:last-child {
width: 80%;
}
#debug-kit-toolbar .panel-content.request {
display: block;
}
/** Neat Array styles **/
#debug-kit-toolbar .neat-array,
#debug-kit-toolbar .neat-array li {
list-style:none;
list-style-image:none;
}
#debug-kit-toolbar .neat-array {
padding: 1px 2px 1px 20px;
background: #CE9E23;
list-style: none;
margin: 0 0 1em 0;
}
#debug-kit-toolbar .neat-array .neat-array {
padding: 0 0 0 20px;
margin: 0;
border-top:1px solid #CE9E23;
}
#debug-kit-toolbar .neat-array li {
background: #FEF6E5;
border-top: 1px solid #CE9E23;
border-bottom: 1px solid #CE9E23;
margin: 0;
line-height: 1.5em;
}
#debug-kit-toolbar .neat-array li:hover {
background: #fff;
}
#debug-kit-toolbar .neat-array li strong {
padding: 0 8px;
font-weight: bold;
}
/* expandable sections */
#debug-kit-toolbar .neat-array li.expandable {
cursor: pointer;
}
#debug-kit-toolbar .neat-array .expanded {
border-bottom:0;
}
#debug-kit-toolbar .neat-array li.expandable.expanded > strong:before {
content: 'v ';
}
#debug-kit-toolbar .neat-array li.expandable.collapsed > strong:before,
#debug-kit-toolbar .neat-array li.expandable.expanded .expandable.collapsed > strong:before {
content: '> ';
}
#debug-kit-toolbar .neat-array li {
cursor: default;
}
#debug-kit-toolbar .debug-kit-graph-bar,
#debug-kit-toolbar .debug-kit-graph-bar-value {
margin: 0;
padding: 0;
border: none;
overflow: hidden;
height: 10px;
}
#debug-kit-toolbar .debug-kit-graph-bar {
background: #ddd;
padding: 2px;
border-radius: 2px;
height: 12px;
}
#debug-kit-toolbar .debug-kit-graph-bar-value {
background: -webkit-linear-gradient(top, #77D124, #4B9406);
background: -moz-linear-gradient(top, #77D124, #4B9406);
border-radius: 3px;
border: 1px solid #4B9406;
}
/* Sql Log */
#sqllog-tab td,
#sqllog-tab .slow-query-container p {
font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced;
}
#debug-kit-toolbar #sqllog-tab a.show-slow {
display:block;
margin: 3px;
float:none;
}
#sqllog-tab .slow-query-container p {
display:block;
clear:both;
margin: 20px 0 5px;
}
#debug-kit-toolbar #sqllog-tab .panel-content-data a {
background: none;
border:none;
}
#sqllog-tab .slow-query {
background:#e79302;
font-size:9px;
color:#fff;
padding: 2px;
white-space:nowrap;
}
#sqllog-tab input[type=submit] {
border: 0;
background: transparent;
cursor: pointer;
font-size: 12px;
font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced;
}
#sqllog-tab input[type=submit]:hover {
color: darkred;
}
#debug-kit-toolbar .alert-duplicate {
color: red;
}
/* previous panels */
#debug-kit-toolbar .panel-history {
display: none;
background:#eeffff;
}
#debug-kit-toolbar #history-tab ul {
margin: 20px 0 0 20px;
}
#debug-kit-toolbar #history-tab li {
margin: 0 0 5px 0;
}
#debug-kit-toolbar #history-tab .panel-content-data a {
float: none;
display:block;
}
#debug-kit-toolbar #history-tab a.active {
background: #FEF6E5;
}
#debug-kit-toolbar #history-tab a.loading:after {
content : ' Loading...';
font-style:italic;
}
/* Minimized mode */
#debug-kit-toolbar.minimized {
opacity: 0.75;
}
#debug-kit-toolbar.minimized:hover {
opacity: inherit;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,936 @@
/**
* Debug Toolbar Javascript.
*
* Creates the DEBUGKIT namespace and provides methods for extending
* and enhancing the Html toolbar. Includes library agnostic Event, Element,
* Cookie and Request wrappers.
*
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since DebugKit 0.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/* jshint jquery: true */
var DEBUGKIT = function () {
var undef;
return {
module: function (newmodule) {
if (this[newmodule] === undef) {
this[newmodule] = {};
return this[newmodule];
}
return this[newmodule];
}
};
}();
(function () {
function versionGTE(a, b) {
var len = Math.min(a.length, b.length);
for (var i = 0; i < len; i++) {
a[i] = parseInt(a[i], 10);
b[i] = parseInt(b[i], 10);
if (a[i] > b[i]) {
return true;
}
if (a[i] < b[i]) {
return false;
}
}
return true;
}
function versionWithin(version, min, max) {
version = version.split('.');
min = min.split('.');
max = max.split('.');
return versionGTE(version, min) && versionGTE(max, version);
}
function initOnReady() {
DEBUGKIT.$(document).ready(function () {
DEBUGKIT.registerModules(DEBUGKIT.$);
DEBUGKIT.loader.init();
});
}
// Push checking for jQuery at the end of the stack.
// This will catch JS included at the bottom of a page.
setTimeout(function() {
// Look for existing jQuery that matches the requirements.
if (window.jQuery && versionWithin(jQuery.fn.jquery, "1.8", "2.1")) {
DEBUGKIT.$ = window.jQuery;
initOnReady();
} else {
var req = new XMLHttpRequest();
req.onload = function () {
eval(this.responseText);
// Restore both $ and jQuery to the original values.
DEBUGKIT.$ = jQuery.noConflict(true);
initOnReady();
};
req.open('get', window.DEBUGKIT_JQUERY_URL, true);
req.send();
}
}, 0);
})();
DEBUGKIT.loader = function () {
return {
// List of methods to run on startup.
_startup: [],
// Register a new method to be run on dom ready.
register: function (method) {
this._startup.push(method);
},
init: function () {
for (var i = 0, callback; callback = this._startup[i]; i++) {
callback.init();
}
}
};
}();
DEBUGKIT.registerModules = function($) {
DEBUGKIT.module('sqlLog');
DEBUGKIT.sqlLog = function () {
return {
init : function () {
var sqlPanel = $('#sql_log-tab');
var buttons = sqlPanel.find('input');
// Button handling code for explain links.
// Performs XHR request to get explain query.
var handleButton = function (event) {
event.preventDefault();
var form = $(this.form),
data = form.serialize(),
dbName = form.find('input[name*=ds]').val() || 'default';
var fetch = $.ajax({
url: this.form.action,
data: data,
type: 'POST',
success : function (response) {
$('#sql-log-explain-' + dbName).html(response);
},
error : function () {
alert('Could not fetch EXPLAIN for query.');
}
});
};
buttons.filter('.sql-explain-link').on('click', handleButton);
}
};
}();
DEBUGKIT.loader.register(DEBUGKIT.sqlLog);
//
// NOTE DEBUGKIT.Util.Element is Deprecated.
//
// Util module and Element utility class.
DEBUGKIT.module('Util');
DEBUGKIT.Util.Element = {
// Test if an element is a name node.
nodeName: function (element, name) {
return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
},
// Return a boolean if the element has the classname
hasClass: function (element, className) {
if (!element.className) {
return false;
}
return element.className.indexOf(className) > -1;
},
addClass: function (element, className) {
if (!element.className) {
element.className = className;
return;
}
element.className = element.className.replace(/^(.*)$/, '$1 ' + className);
},
removeClass: function (element, className) {
if (DEBUGKIT.Util.isArray(element)) {
DEBUGKIT.Util.Collection.apply(element, function (element) {
DEBUGKIT.Util.Element.removeClass(element, className);
});
}
if (!element.className) {
return false;
}
element.className = element.className.replace(new RegExp(' ?(' + className + ') ?'), '');
},
swapClass: function (element, removeClass, addClass) {
if (!element.className) {
return false;
}
element.className = element.className.replace(removeClass, addClass);
},
show: function (element) {
element.style.display = 'block';
},
hide: function (element) {
element.style.display = 'none';
},
// Go between hide() and show() depending on element.style.display
toggle: function (element) {
if (element.style.display === 'none') {
this.show(element);
return;
}
this.hide(element);
},
_walk: function (element, walk) {
var sibling = element[walk];
while (true) {
if (sibling.nodeType == 1) {
break;
}
sibling = sibling[walk];
}
return sibling;
},
getNext: function (element) {
return this._walk(element, 'nextSibling');
},
getPrevious: function (element) {
return this._walk(element, 'previousSibling');
},
// Get or set an element's height, omit value to get, add value (integer) to set.
height: function (element, value) {
// Get value
if (value === undefined) {
return parseInt(this.getStyle(element, 'height'), 10);
}
element.style.height = value + 'px';
},
// Gets the style in css format for property
getStyle: function (element, property) {
if (element.currentStyle) {
property = property.replace(/-[a-z]/g, function (match) {
return match.charAt(1).toUpperCase();
});
return element.currentStyle[property];
}
if (window.getComputedStyle) {
return document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
}
}
};
//
// NOTE DEBUGKIT.Util.Collection is Deprecated.
//
DEBUGKIT.Util.Collection = {
/**
* Apply the passed function to each item in the collection.
* The current element in the collection will be `this` in the callback
* The callback is also passed the element and the index as arguments.
* Optionally you can supply a binding parameter to change `this` in the callback.
*/
apply: function (collection, callback, binding) {
var name, thisVar, i = 0, len = collection.length;
if (len === undefined) {
for (name in collection) {
thisVar = (binding === undefined) ? collection[name] : binding;
callback.apply(thisVar, [collection[name], name]);
}
} else {
for (; i < len; i++) {
thisVar = (binding === undefined) ? collection[i] : binding;
callback.apply(thisVar, [collection[i], i]);
}
}
}
};
//
// NOTE DEBUGKIT.Util.Event is Deprecated.
//
// Event binding
DEBUGKIT.Util.Event = function () {
var _listeners = {},
_eventId = 0;
var preventDefault = function () {
this.returnValue = false;
};
var stopPropagation = function () {
this.cancelBubble = true;
};
// Fixes IE's broken event object, adds in common methods + properties.
var fixEvent = function (event) {
if (!event.preventDefault) {
event.preventDefault = preventDefault;
}
if (!event.stopPropagation) {
event.stopPropagation = stopPropagation;
}
if (!event.target) {
event.target = event.srcElement || document;
}
if (event.pageX === null && event.clientX !== null) {
var doc = document.body;
event.pageX = event.clientX + (doc.scrollLeft || 0) - (doc.clientLeft || 0);
event.pageY = event.clientY + (doc.scrollTop || 0) - (doc.clientTop || 0);
}
return event;
};
return {
// Bind an event listener of type to element, handler is your method.
addEvent: function (element, type, handler, capture) {
capture = (capture === undefined) ? false : capture;
var callback = function (event) {
event = fixEvent(event || window.event);
handler.apply(element, [event]);
};
if (element.addEventListener) {
element.addEventListener(type, callback, capture);
} else if (element.attachEvent) {
type = 'on' + type;
element.attachEvent(type, callback);
} else {
type = 'on' + type;
element[type] = callback;
}
_listeners[++_eventId] = {element: element, type: type, handler: callback};
},
// Destroy an event listener. requires the exact same function as was used for attaching
// the event.
removeEvent: function (element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
type = 'on' + type;
element.detachEvent(type, handler);
} else {
type = 'on' + type;
element[type] = null;
}
},
// Bind an event to the DOMContentLoaded or other similar event.
domready: function (callback) {
if (document.addEventListener) {
return document.addEventListener('DOMContentLoaded', callback, false);
}
if (document.all && !window.opera) {
// Define a "blank" external JavaScript tag
document.write(
'<script type="text/javascript" id="__domreadywatcher" defer="defer" src="javascript:void(0)"><\/script>'
);
var contentloadtag = document.getElementById('__domreadywatcher');
contentloadtag.onreadystatechange = function () {
if (this.readyState === 'complete') {
callback();
}
};
contentloadtag = null;
return;
}
if (/Webkit/i.test(navigator.userAgent)) {
var _timer = setInterval(function () {
if (/loaded|complete/.test(document.readyState)) {
clearInterval(_timer);
callback();
}
}, 10);
}
},
// Unload all the events attached by DebugKit. Fix any memory leaks.
unload: function () {
var listener;
for (var i in _listeners) {
listener = _listeners[i];
try {
this.removeEvent(listener.element, listener.type, listener.handler);
} catch (e) {}
delete _listeners[i];
}
delete _listeners;
}
};
}();
// Cookie utility
DEBUGKIT.Util.Cookie = function () {
var cookieLife = 60;
// Public methods
return {
/**
* Write to cookie.
*
* @param [string] name Name of cookie to write.
* @param [mixed] value Value to write to cookie.
*/
write: function (name, value) {
var date = new Date();
date.setTime(date.getTime() + (cookieLife * 24 * 60 * 60 * 1000));
var expires = '; expires=' + date.toGMTString();
document.cookie = name + '=' + value + expires + '; path=/';
return true;
},
/**
* Read from the cookie.
*
* @param [string] name Name of cookie to read.
*/
read: function (name) {
name = name + '=';
var cookieJar = document.cookie.split(';');
var cookieJarLength = cookieJar.length;
for (var i = 0; i < cookieJarLength; i++) {
var chips = cookieJar[i];
// Trim leading spaces
while (chips.charAt(0) === ' ') {
chips = chips.substring(1, chips.length);
}
if (chips.indexOf(name) === 0) {
return chips.substring(name.length, chips.length);
}
}
return false;
},
/**
* Delete a cookie by name.
*
* @param [string] name of cookie to delete.
*/
del: function (name) {
var date = new Date();
date.setFullYear(2000, 0, 1);
var expires = ' ; expires=' + date.toGMTString();
document.cookie = name + '=' + expires + '; path=/';
}
};
}();
//
// NOTE DEBUGKIT.Util.merge is Deprecated.
//
/**
* Object merge takes any number of arguments and glues them together.
*
* @param [Object] one first object
* @return object
*/
DEBUGKIT.Util.merge = function () {
var out = {};
var argumentsLength = arguments.length;
for (var i = 0; i < argumentsLength; i++) {
var current = arguments[i];
for (var prop in current) {
if (current[prop] !== undefined) {
out[prop] = current[prop];
}
}
}
return out;
};
//
// NOTE DEBUGKIT.Util.isArray is Deprecated.
//
/**
* Check if the given object is an array.
*/
DEBUGKIT.Util.isArray = function (test) {
return Object.prototype.toString.call(test) === '[object Array]';
};
//
// NOTE DEBUGKIT.Util.Request is Deprecated.
//
// Simple wrapper for XmlHttpRequest objects.
DEBUGKIT.Util.Request = function (options) {
var _defaults = {
onComplete : function () {},
onRequest : function () {},
onFail : function () {},
method : 'GET',
async : true,
headers : {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
}
};
var self = this;
this.options = DEBUGKIT.Util.merge(_defaults, options);
this.options.method = this.options.method.toUpperCase();
var ajax = this.createObj();
this.transport = ajax;
// Event assignment
this.onComplete = this.options.onComplete;
this.onRequest = this.options.onRequest;
this.onFail = this.options.onFail;
this.send = function (url, data) {
if (this.options.method === 'GET' && data) {
url = url + ((url.charAt(url.length - 1) === '?') ? '&' : '?') + data; //check for ? at the end of the string
data = null;
}
// Open connection
this.transport.open(this.options.method, url, this.options.async);
// Set statechange and pass the active XHR object to it. From here it handles all status changes.
this.transport.onreadystatechange = function () {
self.onReadyStateChange.apply(self, arguments);
};
for (var key in this.options.headers) {
this.transport.setRequestHeader(key, this.options.headers[key]);
}
if (typeof data === 'object') {
data = this.serialize(data);
}
if (data) {
this.transport.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
this.onRequest();
this.transport.send(data);
};
};
DEBUGKIT.Util.Request.prototype.onReadyStateChange = function () {
if (this.transport.readyState !== 4) {
return;
}
if (this.transport.status === 200 || this.transport.status > 300 && this.transport.status < 400) {
this.response = {
xml: this.transport.responseXML,
text: this.transport.responseText
};
if (typeof this.onComplete === 'function') {
this.onComplete.apply(this, [this, this.response]);
} else {
return this.response;
}
} else if (this.transport.status > 400) {
if (typeof this.onFail === 'function') {
this.onFail.apply(this, []);
} else {
console.error('Request failed');
}
}
};
/**
* Creates cross-broswer XHR object used for requests.
* Tries using the standard XmlHttpRequest, then IE's wacky ActiveX Objects.
*/
DEBUGKIT.Util.Request.prototype.createObj = function () {
var request = null;
try {
request = new XMLHttpRequest();
} catch (MS) {
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
} catch (old_MS) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (failure) {
request = null;
}
}
}
return request;
};
/**
* Serializes an object literal into a querystring.
*/
DEBUGKIT.Util.Request.prototype.serialize = function (data) {
var out = '';
for (var name in data) {
if (data.hasOwnProperty(name)) {
out += name + '=' + data[name] + '&';
}
}
return out.substring(0, out.length - 1);
};
// Basic toolbar module.
DEBUGKIT.toolbar = function () {
// Shortcuts
var Cookie = DEBUGKIT.Util.Cookie,
toolbarHidden = false;
return {
elements: {},
panels: {},
init: function () {
var i, element, lists, index, _this = this;
this.elements.toolbar = $('#debug-kit-toolbar');
if (this.elements.toolbar.length === 0) {
throw new Error('Toolbar not found, make sure you loaded it.');
}
this.elements.panel = $('#panel-tabs');
this.elements.panel.find('.panel-tab').each(function (i, panel) {
_this.addPanel(panel);
});
lists = this.elements.toolbar.find('.depth-0');
this.makeNeatArray(lists);
this.deactivatePanel(true);
},
// Add a panel to the toolbar
addPanel: function (tab) {
var button, content, _this = this;
var panel = {
id : false,
element : tab,
button : undefined,
content : undefined,
active : false
};
tab = $(tab);
button = tab.children('a');
panel.id = button.attr('href').replace(/^#/, '');
panel.button = button;
panel.content = tab.find('.panel-content');
if (!panel.id || panel.content.length === 0) {
return false;
}
this.makePanelDraggable(panel);
this.makePanelMinMax(panel);
button.on('click', function (event) {
event.preventDefault();
_this.togglePanel(panel.id);
});
this.panels[panel.id] = panel;
return panel.id;
},
// Find the handle element and make the panel drag resizable.
makePanelDraggable: function (panel) {
// Create a variable in the enclosing scope, for scope tricks.
var currentElement = null;
// Use the elements startHeight stored Event.pageY and current Event.pageY to
// resize the panel.
var mouseMoveHandler = function (event) {
event.preventDefault();
if (!currentElement) {
return;
}
var newHeight = currentElement.data('startHeight') + (event.pageY - currentElement.data('startY'));
currentElement.parent().height(newHeight);
};
// Handle the mouseup event, remove the other listeners so the panel
// doesn't continue to resize.
var mouseUpHandler = function (event) {
currentElement = null;
$(document).off('mousemove', mouseMoveHandler).off('mouseup', mouseUpHandler);
};
var mouseDownHandler = function (event) {
event.preventDefault();
currentElement = $(this);
currentElement.data('startY', event.pageY);
currentElement.data('startHeight', currentElement.parent().height());
// Attach to document so mouse doesn't have to stay precisely on the 'handle'.
$(document).on('mousemove', mouseMoveHandler)
.on('mouseup', mouseUpHandler);
};
panel.content.find('.panel-resize-handle').on('mousedown', mouseDownHandler);
},
// Make the maximize button work on the panels.
makePanelMinMax: function (panel) {
var _oldHeight;
var maximize = function () {
if (!_oldHeight) {
_oldHeight = this.parentNode.offsetHeight;
}
var windowHeight = window.innerHeight;
var panelHeight = windowHeight - this.parentNode.offsetTop;
$(this.parentNode).height(panelHeight);
$(this).text('-');
};
var minimize = function () {
$(this.parentNode).height(_oldHeight);
$(this).text('+');
_oldHeight = null;
};
var state = 1;
var toggle = function (event) {
event.preventDefault();
if (state === 1) {
maximize.call(this);
state = 0;
} else {
state = 1;
minimize.call(this);
}
};
panel.content.find('.panel-toggle').on('click', toggle);
},
// Toggle a panel
togglePanel: function (id) {
if (this.panels[id] && this.panels[id].active) {
this.deactivatePanel(true);
} else {
this.deactivatePanel(true);
this.activatePanel(id);
}
},
// Make a panel active.
activatePanel: function (id, unique) {
if (this.panels[id] !== undefined && !this.panels[id].active) {
var panel = this.panels[id];
if (panel.content.length > 0) {
panel.content.show();
}
var contentHeight = panel.content.find('.panel-content-data').height() + 70;
if (contentHeight <= (window.innerHeight / 2)) {
panel.content.height(contentHeight);
}
panel.button.addClass('active');
panel.active = true;
return true;
}
return false;
},
// Deactivate a panel. use true to hide all panels.
deactivatePanel: function (id) {
if (id === true) {
for (var i in this.panels) {
this.deactivatePanel(i);
}
return true;
}
if (this.panels[id] !== undefined) {
var panel = this.panels[id];
if (panel.content !== undefined) {
panel.content.hide();
}
panel.button.removeClass('active');
panel.active = false;
return true;
}
return false;
},
// Bind events for all the collapsible arrays.
makeNeatArray: function (lists) {
lists.find('ul').hide()
.parent().addClass('expandable collapsed');
lists.on('click', 'li', function (event) {
event.stopPropagation();
$(this).children('ul').toggle().toggleClass('expanded collapsed');
});
}
};
}();
DEBUGKIT.loader.register(DEBUGKIT.toolbar);
DEBUGKIT.module('historyPanel');
DEBUGKIT.historyPanel = function () {
var toolbar = DEBUGKIT.toolbar,
historyLinks;
// Private methods to handle JSON response and insertion of
// new content.
var switchHistory = function (response) {
historyLinks.removeClass('loading');
$.each(toolbar.panels, function (id, panel) {
if (panel.content === undefined || response[id] === undefined) {
return;
}
var regionDiv = panel.content.find('.panel-resize-region');
if (!regionDiv.length) {
return;
}
var regionDivs = regionDiv.children();
regionDivs.filter('div').hide();
regionDivs.filter('.panel-history').each(function (i, panelContent) {
var panelId = panelContent.id.replace('-history', '');
if (response[panelId]) {
panelContent = $(panelContent);
panelContent.html(response[panelId]);
var lists = panelContent.find('.depth-0');
toolbar.makeNeatArray(lists);
}
panelContent.show();
});
});
};
// Private method to handle restoration to current request.
var restoreCurrentState = function () {
var id, i, panelContent, tag;
historyLinks.removeClass('loading');
$.each(toolbar.panels, function (panel, id) {
if (panel.content === undefined) {
return;
}
var regionDiv = panel.content.find('.panel-resize-region');
if (!regionDiv.length) {
return;
}
var regionDivs = regionDiv.children();
regionDivs.filter('div').show()
.end()
.filter('.panel-history').hide();
});
};
function handleHistoryLink(event) {
event.preventDefault();
historyLinks.removeClass('active');
$(this).addClass('active loading');
if (this.id === 'history-restore-current') {
restoreCurrentState();
return false;
}
var xhr = $.ajax({
url: this.href,
type: 'GET',
dataType: 'json'
});
xhr.success(switchHistory).fail(function () {
alert('History retrieval failed');
});
}
return {
init : function () {
if (toolbar.panels.history === undefined) {
return;
}
historyLinks = toolbar.panels.history.content.find('.history-link');
historyLinks.on('click', handleHistoryLink);
}
};
}();
DEBUGKIT.loader.register(DEBUGKIT.historyPanel);
//Add events + behaviors for toolbar collapser.
DEBUGKIT.toolbarToggle = function () {
var toolbar = DEBUGKIT.toolbar,
Cookie = DEBUGKIT.Util.Cookie,
toolbarHidden = false;
return {
init: function () {
var button = $('#hide-toolbar'),
self = this;
button.on('click', function (event) {
event.preventDefault();
self.toggleToolbar();
});
var toolbarState = Cookie.read('toolbarDisplay');
if (toolbarState !== 'show') {
toolbarHidden = false;
this.toggleToolbar();
}
},
toggleToolbar: function () {
var display = toolbarHidden ? 'show' : 'hide';
$.each(toolbar.panels, function (i, panel) {
$(panel.element)[display]();
Cookie.write('toolbarDisplay', display);
});
toolbarHidden = !toolbarHidden;
if (toolbarHidden) {
$('#debug-kit-toolbar').addClass('minimized');
} else {
$('#debug-kit-toolbar').removeClass('minimized');
}
return false;
}
};
}();
DEBUGKIT.loader.register(DEBUGKIT.toolbarToggle);
}; // DEBUGKIT.registerModules

61
exp/error/400.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 400 - Bad Request!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status4xx">
<h1>ERROR 400 - Bad Request!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>You have used invalid syntax.</p>
<P>Please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//--> with any queries.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/401.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 401 - Unauthorized!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status4xx">
<h1>ERROR 401 - Unauthorized!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>The URL requested requires authorisation.</p>
<P>Please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//--> with any queries.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/403.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 403 - Forbidden!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status4xx">
<h1>ERROR 403 - Forbidden!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>You are not permitted to access the requested URL.</p>
<P>Please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//--> with any queries.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/404.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 404 - Not Found!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status4xx">
<h1>ERROR 404 - Not Found!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>The requested URL was not found on this server.</p>
<P>Please check the URL or contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//-->.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/405.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 405 - Method Not Allowed!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status4xx">
<h1>ERROR 405 - Method Not Allowed!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>The method used is not permitted.</p>
<P>Please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//--> with any queries.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/500.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 500 - Internal Server Error!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status5xx">
<h1>ERROR 500 - Internal Server Error!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>The requested URL caused an internal server error.</p>
<P>If you get this message repeatedly please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//-->.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/502.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 502 - Bad Gateway!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status5xx">
<h1>ERROR 502 - Bad Gateway!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>This server received an invalid response from an upstream server it accessed to fulfill the request.</p>
<P>If you get this message repeatedly please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//-->.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

61
exp/error/503.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>ERROR 503 - Service Unavailable!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<style type="text/css"><!--
body {
color: #444444;
background-color: #EEEEEE;
font-family: 'Trebuchet MS', sans-serif;
font-size: 80%;
}
h1 {}
h2 { font-size: 1.2em; }
#page{
background-color: #FFFFFF;
width: 60%;
margin: 24px auto;
padding: 12px;
}
#header {
padding: 6px ;
text-align: center;
}
.status3xx { background-color: #475076; color: #FFFFFF; }
.status4xx { background-color: #C55042; color: #FFFFFF; }
.status5xx { background-color: #F2E81A; color: #000000; }
#content {
padding: 4px 0 24px 0;
}
#footer {
color: #666666;
background: #f9f9f9;
padding: 10px 20px;
border-top: 5px #efefef solid;
font-size: 0.8em;
text-align: center;
}
#footer a {
color: #999999;
}
--></style>
</head>
<body>
<div id="page">
<div id="header" class="status5xx">
<h1>ERROR 503 - Service Unavailable!</h1>
</div>
<div id="content">
<h2>The following error occurred:</h2>
<p>The Service is not available at the moment due to a temporary overloading or maintenance of the server. Please try again later.</p>
<P>Please contact the <!--WEBMASTER//-->webmaster<!--WEBMASTER//--> with any queries.</p>
</div>
<div id="footer">
<p>Powered by <a href="http://www.ispconfig.org">ISPConfig</a></p>
</div>
</div>
</body>
</html>

0
exp/plugins/empty Normal file
View File

4
exp/stats/.htaccess Normal file
View File

@@ -0,0 +1,4 @@
AuthType Basic
AuthName "Members Only"
AuthUserFile /var/www/clients/client1/web3/web/stats/.htpasswd_stats
require valid-user

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Some files were not shown because too many files have changed in this diff Show More