mirror of
https://github.com/dg/dibi.git
synced 2025-08-05 13:47:33 +02:00
changed profiler API; IDibiProfiler replaced with DibiConnection::$onEvent; DibiProfiler split to DibiFileLogger, DibiFirePhpLogger and DibiNettePanel (BC break!)
This commit is contained in:
164
dibi/Nette/DibiNettePanel.php
Normal file
164
dibi/Nette/DibiNettePanel.php
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the "dibi" - smart database abstraction layer.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the file license.txt that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (interface_exists('Nette\Diagnostics\IBarPanel')) {
|
||||||
|
class_alias('Nette\Diagnostics\IBarPanel', 'IBarPanel');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dibi panel for Nette\Diagnostics.
|
||||||
|
*
|
||||||
|
* @author David Grudl
|
||||||
|
*/
|
||||||
|
class DibiNettePanel extends DibiObject implements IBarPanel
|
||||||
|
{
|
||||||
|
/** @var int maximum SQL length */
|
||||||
|
static public $maxLength = 1000;
|
||||||
|
|
||||||
|
/** @var bool explain queries? */
|
||||||
|
public $explain;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $filter;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $events = array();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($explain = TRUE, $filter = NULL)
|
||||||
|
{
|
||||||
|
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
|
||||||
|
$this->explain = (bool) $explain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function register(DibiConnection $connection)
|
||||||
|
{
|
||||||
|
if (is_callable('Nette\Diagnostics\Debugger::enable')) {
|
||||||
|
class_alias('Nette\Diagnostics\Debugger', 'NDebugger'); // PHP 5.2 code compatibility
|
||||||
|
}
|
||||||
|
if (is_callable('NDebugger::enable')) {
|
||||||
|
NDebugger::$bar->addPanel($this);
|
||||||
|
NDebugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
|
||||||
|
$connection->onEvent[] = array($this, 'logEvent');
|
||||||
|
} elseif (is_callable('Debugger::enable')) {
|
||||||
|
Debugger::$bar->addPanel($this);
|
||||||
|
Debugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
|
||||||
|
$connection->onEvent[] = array($this, 'logEvent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After event notification.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function logEvent(DibiEvent $event)
|
||||||
|
{
|
||||||
|
if (($event->type & $this->filter) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->events[] = $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns blue-screen custom tab.
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function renderException($e)
|
||||||
|
{
|
||||||
|
if ($e instanceof DibiException && $e->getSql()) {
|
||||||
|
return array(
|
||||||
|
'tab' => 'SQL',
|
||||||
|
'panel' => dibi::dump($e->getSql(), TRUE),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTML code for custom tab. (Nette\Diagnostics\IBarPanel)
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getTab()
|
||||||
|
{
|
||||||
|
return '<span title="dibi"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
|
||||||
|
. dibi::$numOfQueries . ' queries'
|
||||||
|
. (dibi::$totalTime ? ' / ' . sprintf('%0.1f', dibi::$totalTime * 1000) . 'ms' : '')
|
||||||
|
. '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTML code for custom panel. (Nette\Diagnostics\IBarPanel)
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getPanel()
|
||||||
|
{
|
||||||
|
$s = NULL;
|
||||||
|
$h = 'htmlSpecialChars';
|
||||||
|
foreach ($this->events as $event) {
|
||||||
|
$explain = NULL; // EXPLAIN is called here to work SELECT FOUND_ROWS()
|
||||||
|
if ($this->explain && $event->type === DibiEvent::SELECT) {
|
||||||
|
try {
|
||||||
|
$backup = array($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime);
|
||||||
|
$event->connection->onEvent = NULL;
|
||||||
|
$explain = dibi::dump($event->connection->nativeQuery('EXPLAIN ' . $event->sql), TRUE);
|
||||||
|
} catch (DibiException $e) {}
|
||||||
|
list($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime) = $backup;
|
||||||
|
}
|
||||||
|
|
||||||
|
$s .= '<tr><td>' . sprintf('%0.3f', $event->time * 1000);
|
||||||
|
if ($explain) {
|
||||||
|
static $counter;
|
||||||
|
$counter++;
|
||||||
|
$s .= "<br /><a href='#' class='nette-toggler' rel='#nette-debug-DibiProfiler-row-$counter'>explain ►</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$s .= '</td><td class="nette-DibiProfiler-sql">' . dibi::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, TRUE);
|
||||||
|
if ($explain) {
|
||||||
|
$s .= "<div id='nette-debug-DibiProfiler-row-$counter' class='nette-collapsed'>{$explain}</div>";
|
||||||
|
}
|
||||||
|
if ($event->source) {
|
||||||
|
$helpers = 'Nette\Diagnostics\Helpers';
|
||||||
|
if (!class_exists($helpers)) {
|
||||||
|
$helpers = class_exists('NDebugHelpers') ? 'NDebugHelpers' : 'DebugHelpers';
|
||||||
|
}
|
||||||
|
$s .= call_user_func(array($helpers, 'editorLink'), $event->source[0], $event->source[1])->class('nette-DibiProfiler-source');
|
||||||
|
}
|
||||||
|
|
||||||
|
$s .= "</td><td>{$event->count}</td><td>{$h($event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'))}</td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($this->events) ? '' :
|
||||||
|
'<style> #nette-debug td.nette-DibiProfiler-sql { background: white !important }
|
||||||
|
#nette-debug .nette-DibiProfiler-source { color: #999 !important }
|
||||||
|
#nette-debug nette-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
|
||||||
|
<h1>Queries: ' . dibi::$numOfQueries . (dibi::$totalTime === NULL ? '' : ', time: ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms') . '</h1>
|
||||||
|
<div class="nette-inner nette-DibiProfiler">
|
||||||
|
<table>
|
||||||
|
<tr><th>Time ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '
|
||||||
|
</table>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -23,18 +23,6 @@ if (version_compare(PHP_VERSION, '5.2.0', '<')) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compatibility with Nette
|
|
||||||
*/
|
|
||||||
if (interface_exists('Nette\Diagnostics\IBarPanel')) {
|
|
||||||
class_alias('Nette\Diagnostics\IBarPanel', 'IBarPanel');
|
|
||||||
|
|
||||||
} elseif (!interface_exists('IBarPanel')) {
|
|
||||||
interface IBarPanel {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
require_once dirname(__FILE__) . '/libs/interfaces.php';
|
require_once dirname(__FILE__) . '/libs/interfaces.php';
|
||||||
require_once dirname(__FILE__) . '/libs/DibiDateTime.php';
|
require_once dirname(__FILE__) . '/libs/DibiDateTime.php';
|
||||||
require_once dirname(__FILE__) . '/libs/DibiObject.php';
|
require_once dirname(__FILE__) . '/libs/DibiObject.php';
|
||||||
@@ -48,7 +36,10 @@ require_once dirname(__FILE__) . '/libs/DibiTranslator.php';
|
|||||||
require_once dirname(__FILE__) . '/libs/DibiDataSource.php';
|
require_once dirname(__FILE__) . '/libs/DibiDataSource.php';
|
||||||
require_once dirname(__FILE__) . '/libs/DibiFluent.php';
|
require_once dirname(__FILE__) . '/libs/DibiFluent.php';
|
||||||
require_once dirname(__FILE__) . '/libs/DibiDatabaseInfo.php';
|
require_once dirname(__FILE__) . '/libs/DibiDatabaseInfo.php';
|
||||||
require_once dirname(__FILE__) . '/libs/DibiProfiler.php';
|
require_once dirname(__FILE__) . '/libs/DibiEvent.php';
|
||||||
|
require_once dirname(__FILE__) . '/libs/DibiFileLogger.php';
|
||||||
|
require_once dirname(__FILE__) . '/libs/DibiFirePhpLogger.php';
|
||||||
|
require_once dirname(__FILE__) . '/Nette/DibiNettePanel.php';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -234,18 +225,6 @@ class dibi
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve active connection profiler.
|
|
||||||
* @return IDibiProfiler
|
|
||||||
* @throws DibiException
|
|
||||||
*/
|
|
||||||
public static function getProfiler()
|
|
||||||
{
|
|
||||||
return self::getConnection()->getProfiler();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************* monostate for active connection ****************d*g**/
|
/********************* monostate for active connection ****************d*g**/
|
||||||
|
|
||||||
|
|
||||||
|
@@ -23,11 +23,13 @@
|
|||||||
* @property-read IDibiDriver $driver
|
* @property-read IDibiDriver $driver
|
||||||
* @property-read int $affectedRows
|
* @property-read int $affectedRows
|
||||||
* @property-read int $insertId
|
* @property-read int $insertId
|
||||||
* @property IDibiProfiler $profiler
|
|
||||||
* @property-read DibiDatabaseInfo $databaseInfo
|
* @property-read DibiDatabaseInfo $databaseInfo
|
||||||
*/
|
*/
|
||||||
class DibiConnection extends DibiObject
|
class DibiConnection extends DibiObject
|
||||||
{
|
{
|
||||||
|
/** @var array of function(DibiEvent $event); Occurs after query is executed */
|
||||||
|
public $onEvent;
|
||||||
|
|
||||||
/** @var array Current connection configuration */
|
/** @var array Current connection configuration */
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
@@ -37,9 +39,6 @@ class DibiConnection extends DibiObject
|
|||||||
/** @var DibiTranslator */
|
/** @var DibiTranslator */
|
||||||
private $translator;
|
private $translator;
|
||||||
|
|
||||||
/** @var IDibiProfiler */
|
|
||||||
private $profiler;
|
|
||||||
|
|
||||||
/** @var bool Is connected? */
|
/** @var bool Is connected? */
|
||||||
private $connected = FALSE;
|
private $connected = FALSE;
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ class DibiConnection extends DibiObject
|
|||||||
* - formatDateTime => date-time format (if empty, DateTime objects will be returned)
|
* - formatDateTime => date-time format (if empty, DateTime objects will be returned)
|
||||||
* - profiler (array or bool)
|
* - profiler (array or bool)
|
||||||
* - run (bool) => enable profiler?
|
* - run (bool) => enable profiler?
|
||||||
* - class => profiler class name (default is DibiProfiler)
|
* - file => file to log
|
||||||
* - substitutes (array) => map of driver specific substitutes (under development)
|
* - substitutes (array) => map of driver specific substitutes (under development)
|
||||||
|
|
||||||
* @param mixed connection parameters
|
* @param mixed connection parameters
|
||||||
@@ -107,20 +106,22 @@ class DibiConnection extends DibiObject
|
|||||||
|
|
||||||
// profiler
|
// profiler
|
||||||
$profilerCfg = & $config['profiler'];
|
$profilerCfg = & $config['profiler'];
|
||||||
if (is_scalar($profilerCfg)) { // back compatibility
|
if (is_scalar($profilerCfg)) {
|
||||||
$profilerCfg = array(
|
$profilerCfg = array('run' => (bool) $profilerCfg);
|
||||||
'run' => (bool) $profilerCfg,
|
|
||||||
'class' => strlen($profilerCfg) > 1 ? $profilerCfg : NULL,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($profilerCfg['run'])) {
|
if (!empty($profilerCfg['run'])) {
|
||||||
class_exists('dibi'); // ensure dibi.php is processed
|
$filter = isset($profilerCfg['filter']) ? $profilerCfg['filter'] : DibiEvent::QUERY;
|
||||||
$class = isset($profilerCfg['class']) ? $profilerCfg['class'] : 'DibiProfiler';
|
|
||||||
if (!class_exists($class)) {
|
if (isset($profilerCfg['file'])) {
|
||||||
throw new DibiException("Unable to create instance of dibi profiler '$class'.");
|
$this->onEvent[] = array(new DibiFileLogger($profilerCfg['file'], $filter), 'logEvent');
|
||||||
}
|
}
|
||||||
$this->setProfiler(new $class($profilerCfg));
|
|
||||||
|
if (DibiFirePhpLogger::isAvailable()) {
|
||||||
|
$this->onEvent[] = array(new DibiFirePhpLogger($filter), 'logEvent');
|
||||||
|
}
|
||||||
|
|
||||||
|
$panel = new DibiNettePanel(isset($profilerCfg['explain']) ? $profilerCfg['explain'] : TRUE, $filter);
|
||||||
|
$panel->register($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->substitutes = new DibiHashMap(create_function('$expr', 'return ":$expr:";'));
|
$this->substitutes = new DibiHashMap(create_function('$expr', 'return ":$expr:";'));
|
||||||
@@ -155,13 +156,15 @@ class DibiConnection extends DibiObject
|
|||||||
*/
|
*/
|
||||||
final public function connect()
|
final public function connect()
|
||||||
{
|
{
|
||||||
if ($this->profiler !== NULL) {
|
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::CONNECT) : NULL;
|
||||||
$ticket = $this->profiler->before($this, IDibiProfiler::CONNECT);
|
try {
|
||||||
}
|
$this->driver->connect($this->config);
|
||||||
$this->driver->connect($this->config);
|
$this->connected = TRUE;
|
||||||
$this->connected = TRUE;
|
$event && $this->onEvent($event->done());
|
||||||
if (isset($ticket)) {
|
|
||||||
$this->profiler->after($ticket);
|
} catch (DibiException $e) {
|
||||||
|
$event && $this->onEvent($event->done($e));
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,28 +332,24 @@ class DibiConnection extends DibiObject
|
|||||||
{
|
{
|
||||||
$this->connected || $this->connect();
|
$this->connected || $this->connect();
|
||||||
|
|
||||||
if ($this->profiler !== NULL) {
|
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::QUERY, $sql) : NULL;
|
||||||
$event = IDibiProfiler::QUERY;
|
dibi::$numOfQueries++;
|
||||||
if (preg_match('#\s*(SELECT|UPDATE|INSERT|DELETE)#iA', $sql, $matches)) {
|
dibi::$sql = $sql;
|
||||||
static $events = array(
|
try {
|
||||||
'SELECT' => IDibiProfiler::SELECT, 'UPDATE' => IDibiProfiler::UPDATE,
|
$res = $this->driver->query($sql);
|
||||||
'INSERT' => IDibiProfiler::INSERT, 'DELETE' => IDibiProfiler::DELETE,
|
|
||||||
);
|
} catch (DibiException $e) {
|
||||||
$event = $events[strtoupper($matches[1])];
|
$event && $this->onEvent($event->done($e));
|
||||||
}
|
throw $e;
|
||||||
$ticket = $this->profiler->before($this, $event, $sql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dibi::$sql = $sql;
|
if ($res) {
|
||||||
if ($res = $this->driver->query($sql)) { // intentionally =
|
|
||||||
$res = $this->createResultSet($res);
|
$res = $this->createResultSet($res);
|
||||||
} else {
|
} else {
|
||||||
$res = $this->driver->getAffectedRows();
|
$res = $this->driver->getAffectedRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($ticket)) {
|
$event && $this->onEvent($event->done($res));
|
||||||
$this->profiler->after($ticket, $res);
|
|
||||||
}
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,12 +419,14 @@ class DibiConnection extends DibiObject
|
|||||||
public function begin($savepoint = NULL)
|
public function begin($savepoint = NULL)
|
||||||
{
|
{
|
||||||
$this->connected || $this->connect();
|
$this->connected || $this->connect();
|
||||||
if ($this->profiler !== NULL) {
|
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::BEGIN, $savepoint) : NULL;
|
||||||
$ticket = $this->profiler->before($this, IDibiProfiler::BEGIN, $savepoint);
|
try {
|
||||||
}
|
$this->driver->begin($savepoint);
|
||||||
$this->driver->begin($savepoint);
|
$event && $this->onEvent($event->done());
|
||||||
if (isset($ticket)) {
|
|
||||||
$this->profiler->after($ticket);
|
} catch (DibiException $e) {
|
||||||
|
$event && $this->onEvent($event->done($e));
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,12 +440,14 @@ class DibiConnection extends DibiObject
|
|||||||
public function commit($savepoint = NULL)
|
public function commit($savepoint = NULL)
|
||||||
{
|
{
|
||||||
$this->connected || $this->connect();
|
$this->connected || $this->connect();
|
||||||
if ($this->profiler !== NULL) {
|
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::COMMIT, $savepoint) : NULL;
|
||||||
$ticket = $this->profiler->before($this, IDibiProfiler::COMMIT, $savepoint);
|
try {
|
||||||
}
|
$this->driver->commit($savepoint);
|
||||||
$this->driver->commit($savepoint);
|
$event && $this->onEvent($event->done());
|
||||||
if (isset($ticket)) {
|
|
||||||
$this->profiler->after($ticket);
|
} catch (DibiException $e) {
|
||||||
|
$event && $this->onEvent($event->done($e));
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,12 +461,14 @@ class DibiConnection extends DibiObject
|
|||||||
public function rollback($savepoint = NULL)
|
public function rollback($savepoint = NULL)
|
||||||
{
|
{
|
||||||
$this->connected || $this->connect();
|
$this->connected || $this->connect();
|
||||||
if ($this->profiler !== NULL) {
|
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::ROLLBACK, $savepoint) : NULL;
|
||||||
$ticket = $this->profiler->before($this, IDibiProfiler::ROLLBACK, $savepoint);
|
try {
|
||||||
}
|
$this->driver->rollback($savepoint);
|
||||||
$this->driver->rollback($savepoint);
|
$event && $this->onEvent($event->done());
|
||||||
if (isset($ticket)) {
|
|
||||||
$this->profiler->after($ticket);
|
} catch (DibiException $e) {
|
||||||
|
$event && $this->onEvent($event->done($e));
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,32 +556,6 @@ class DibiConnection extends DibiObject
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************* profiler ****************d*g**/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param IDibiProfiler
|
|
||||||
* @return DibiConnection provides a fluent interface
|
|
||||||
*/
|
|
||||||
public function setProfiler(IDibiProfiler $profiler = NULL)
|
|
||||||
{
|
|
||||||
$this->profiler = $profiler;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return IDibiProfiler
|
|
||||||
*/
|
|
||||||
public function getProfiler()
|
|
||||||
{
|
|
||||||
return $this->profiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************* substitutions ****************d*g**/
|
/********************* substitutions ****************d*g**/
|
||||||
|
|
||||||
|
|
||||||
|
103
dibi/libs/DibiEvent.php
Normal file
103
dibi/libs/DibiEvent.php
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the "dibi" - smart database abstraction layer.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the file license.txt that was distributed with this source code.
|
||||||
|
*
|
||||||
|
* @package dibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profiler & logger event.
|
||||||
|
*
|
||||||
|
* @author David Grudl
|
||||||
|
*/
|
||||||
|
class DibiEvent
|
||||||
|
{
|
||||||
|
/** event type */
|
||||||
|
const CONNECT = 1,
|
||||||
|
SELECT = 4,
|
||||||
|
INSERT = 8,
|
||||||
|
DELETE = 16,
|
||||||
|
UPDATE = 32,
|
||||||
|
QUERY = 60, // SELECT | INSERT | DELETE | UPDATE
|
||||||
|
BEGIN = 64,
|
||||||
|
COMMIT = 128,
|
||||||
|
ROLLBACK = 256,
|
||||||
|
TRANSACTION = 448, // BEGIN | COMMIT | ROLLBACK
|
||||||
|
ALL = 1023;
|
||||||
|
|
||||||
|
/** @var DibiConnection */
|
||||||
|
public $connection;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $type;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public $sql;
|
||||||
|
|
||||||
|
/** @var DibiResult|DibiDriverException|NULL */
|
||||||
|
public $result;
|
||||||
|
|
||||||
|
/** @var float */
|
||||||
|
public $time;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $count;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
public $source;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(DibiConnection $connection, $type, $sql = NULL)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
$this->type = $type;
|
||||||
|
$this->sql = trim($sql);
|
||||||
|
$this->time = -microtime(TRUE);
|
||||||
|
|
||||||
|
if ($type === self::QUERY && preg_match('#(SELECT|UPDATE|INSERT|DELETE)#iA', $this->sql, $matches)) {
|
||||||
|
static $types = array(
|
||||||
|
'SELECT' => self::SELECT, 'UPDATE' => self::UPDATE,
|
||||||
|
'INSERT' => self::INSERT, 'DELETE' => self::DELETE,
|
||||||
|
);
|
||||||
|
$this->type = $types[strtoupper($matches[1])];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass('dibi');
|
||||||
|
$dibiDir = dirname($rc->getFileName()) . DIRECTORY_SEPARATOR;
|
||||||
|
foreach (debug_backtrace(FALSE) as $row) {
|
||||||
|
if (isset($row['file']) && is_file($row['file']) && strpos($row['file'], $dibiDir) !== 0) {
|
||||||
|
$this->source = array($row['file'], (int) $row['line']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dibi::$elapsedTime = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function done($result = NULL)
|
||||||
|
{
|
||||||
|
$this->result = $result;
|
||||||
|
try {
|
||||||
|
$this->count = $result instanceof DibiResult ? count($result) : NULL;
|
||||||
|
} catch (DibiException $e) {
|
||||||
|
$this->count = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->time += microtime(TRUE);
|
||||||
|
dibi::$elapsedTime = $this->time;
|
||||||
|
dibi::$totalTime += $this->time;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -42,7 +42,6 @@ class DibiException extends Exception
|
|||||||
{
|
{
|
||||||
parent::__construct($message, (int) $code);
|
parent::__construct($message, (int) $code);
|
||||||
$this->sql = $sql;
|
$this->sql = $sql;
|
||||||
// TODO: add $profiler->exception($this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
79
dibi/libs/DibiFileLogger.php
Normal file
79
dibi/libs/DibiFileLogger.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the "dibi" - smart database abstraction layer.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the file license.txt that was distributed with this source code.
|
||||||
|
*
|
||||||
|
* @package dibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dibi file logger.
|
||||||
|
*
|
||||||
|
* @author David Grudl
|
||||||
|
*/
|
||||||
|
class DibiFileLogger extends DibiObject
|
||||||
|
{
|
||||||
|
/** @var string Name of the file where SQL errors should be logged */
|
||||||
|
public $file;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $filter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($file, $filter = NULL)
|
||||||
|
{
|
||||||
|
$this->file = $file;
|
||||||
|
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After event notification.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function logEvent(DibiEvent $event)
|
||||||
|
{
|
||||||
|
if (($event->type & $this->filter) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$handle = fopen($this->file, 'a');
|
||||||
|
if (!$handle) return; // or throw exception?
|
||||||
|
flock($handle, LOCK_EX);
|
||||||
|
|
||||||
|
if ($event->result instanceof Exception) {
|
||||||
|
$message = $event->result->getMessage();
|
||||||
|
if ($code = $event->result->getCode()) {
|
||||||
|
$message = "[$code] $message";
|
||||||
|
}
|
||||||
|
fwrite($handle,
|
||||||
|
"ERROR: $message"
|
||||||
|
. "\n-- SQL: " . $event->sql
|
||||||
|
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
|
||||||
|
. ";\n-- " . date('Y-m-d H:i:s')
|
||||||
|
. "\n\n"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fwrite($handle,
|
||||||
|
"OK: " . $event->sql
|
||||||
|
. ($event->count ? ";\n-- rows: " . $event->count : '')
|
||||||
|
. "\n-- takes: " . sprintf('%0.3f', $event->time * 1000) . ' ms'
|
||||||
|
. "\n-- source: " . implode(':', $event->source)
|
||||||
|
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
|
||||||
|
. "\n-- " . date('Y-m-d H:i:s')
|
||||||
|
. "\n\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
89
dibi/libs/DibiFirePhpLogger.php
Normal file
89
dibi/libs/DibiFirePhpLogger.php
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the "dibi" - smart database abstraction layer.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the file license.txt that was distributed with this source code.
|
||||||
|
*
|
||||||
|
* @package dibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dibi FirePHP logger.
|
||||||
|
*
|
||||||
|
* @author David Grudl
|
||||||
|
*/
|
||||||
|
class DibiFirePhpLogger extends DibiObject
|
||||||
|
{
|
||||||
|
/** maximum number of rows */
|
||||||
|
static public $maxQueries = 30;
|
||||||
|
|
||||||
|
/** maximum SQL length */
|
||||||
|
static public $maxLength = 1000;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $filter;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private static $fireTable = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isAvailable()
|
||||||
|
{
|
||||||
|
return isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($filter = NULL)
|
||||||
|
{
|
||||||
|
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After event notification.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function logEvent(DibiEvent $event)
|
||||||
|
{
|
||||||
|
if (headers_sent() || ($event->type & $this->filter) === 0 || count(self::$fireTable) > self::$maxQueries) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$fireTable[] = array(
|
||||||
|
sprintf('%0.3f', $event->time * 1000),
|
||||||
|
strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql,
|
||||||
|
$event->result instanceof Exception ? 'ERROR' : $event->count,
|
||||||
|
$event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
|
||||||
|
);
|
||||||
|
|
||||||
|
header('X-Wf-Protocol-dibi: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
|
||||||
|
header('X-Wf-dibi-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');
|
||||||
|
header('X-Wf-dibi-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
|
||||||
|
|
||||||
|
$payload = json_encode(array(
|
||||||
|
array(
|
||||||
|
'Type' => 'TABLE',
|
||||||
|
'Label' => 'dibi profiler (' . dibi::$numOfQueries . ' SQL queries took ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms)',
|
||||||
|
),
|
||||||
|
self::$fireTable,
|
||||||
|
));
|
||||||
|
foreach (str_split($payload, 4990) as $num => $s) {
|
||||||
|
$num++;
|
||||||
|
header("X-Wf-dibi-1-1-d$num: |$s|\\"); // protocol-, structure-, plugin-, message-index
|
||||||
|
}
|
||||||
|
header("X-Wf-dibi-1-1-d$num: |$s|");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,327 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file is part of the "dibi" - smart database abstraction layer.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view
|
|
||||||
* the file license.txt that was distributed with this source code.
|
|
||||||
*
|
|
||||||
* @package dibi
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dibi basic logger & profiler (experimental).
|
|
||||||
*
|
|
||||||
* Profiler options:
|
|
||||||
* - 'explain' - explain SELECT queries?
|
|
||||||
* - 'filter' - which queries to log?
|
|
||||||
*
|
|
||||||
* @author David Grudl
|
|
||||||
*/
|
|
||||||
class DibiProfiler extends DibiObject implements IDibiProfiler, IBarPanel
|
|
||||||
{
|
|
||||||
/** maximum number of rows */
|
|
||||||
static public $maxQueries = 30;
|
|
||||||
|
|
||||||
/** maximum SQL length */
|
|
||||||
static public $maxLength = 1000;
|
|
||||||
|
|
||||||
/** @var string Name of the file where SQL errors should be logged */
|
|
||||||
private $file;
|
|
||||||
|
|
||||||
/** @var bool log to firebug? */
|
|
||||||
public $useFirebug;
|
|
||||||
|
|
||||||
/** @var bool explain queries? */
|
|
||||||
public $explainQuery = TRUE;
|
|
||||||
|
|
||||||
/** @var int */
|
|
||||||
private $filter = self::ALL;
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
public static $tickets = array();
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
public static $fireTable = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(array $config)
|
|
||||||
{
|
|
||||||
if (is_callable('Nette\Diagnostics\Debugger::enable')) {
|
|
||||||
eval('$tmp = Nette\Diagnostics\Debugger::$bar;');
|
|
||||||
$tmp->addPanel($this);
|
|
||||||
eval('$tmp = Nette\Diagnostics\Debugger::$blueScreen;');
|
|
||||||
$tmp->addPanel(array($this, 'renderException'), __CLASS__);
|
|
||||||
} elseif (is_callable('NDebugger::enable')) {
|
|
||||||
NDebugger::$bar->addPanel($this);
|
|
||||||
NDebugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
|
|
||||||
} elseif (is_callable('Debugger::enable')) {
|
|
||||||
Debugger::$bar->addPanel($this);
|
|
||||||
Debugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->useFirebug = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
|
|
||||||
|
|
||||||
if (isset($config['file'])) {
|
|
||||||
$this->setFile($config['file']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['filter'])) {
|
|
||||||
$this->setFilter($config['filter']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['explain'])) {
|
|
||||||
$this->explainQuery = (bool) $config['explain'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function renderException($e)
|
|
||||||
{
|
|
||||||
if ($e instanceof DibiException && $e->getSql()) {
|
|
||||||
return array(
|
|
||||||
'tab' => 'SQL',
|
|
||||||
'panel' => dibi::dump($e->getSql(), TRUE),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string filename
|
|
||||||
* @return DibiProfiler provides a fluent interface
|
|
||||||
*/
|
|
||||||
public function setFile($file)
|
|
||||||
{
|
|
||||||
$this->file = $file;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int
|
|
||||||
* @return DibiProfiler provides a fluent interface
|
|
||||||
*/
|
|
||||||
public function setFilter($filter)
|
|
||||||
{
|
|
||||||
$this->filter = (int) $filter;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before event notification.
|
|
||||||
* @param DibiConnection
|
|
||||||
* @param int event name
|
|
||||||
* @param string sql
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function before(DibiConnection $connection, $event, $sql = NULL)
|
|
||||||
{
|
|
||||||
$rc = new ReflectionClass('dibi');
|
|
||||||
$dibiDir = dirname($rc->getFileName()) . DIRECTORY_SEPARATOR;
|
|
||||||
$source = NULL;
|
|
||||||
foreach (debug_backtrace(FALSE) as $row) {
|
|
||||||
if (isset($row['file']) && is_file($row['file']) && strpos($row['file'], $dibiDir) !== 0) {
|
|
||||||
$source = array($row['file'], (int) $row['line']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($event & self::QUERY) dibi::$numOfQueries++;
|
|
||||||
dibi::$elapsedTime = FALSE;
|
|
||||||
self::$tickets[] = array($connection, $event, trim($sql), -microtime(TRUE), NULL, $source);
|
|
||||||
end(self::$tickets);
|
|
||||||
return key(self::$tickets);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After event notification.
|
|
||||||
* @param int
|
|
||||||
* @param DibiResult
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function after($ticket, $res = NULL)
|
|
||||||
{
|
|
||||||
if (!isset(self::$tickets[$ticket])) {
|
|
||||||
throw new InvalidArgumentException('Bad ticket number.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$ticket = & self::$tickets[$ticket];
|
|
||||||
$ticket[3] += microtime(TRUE);
|
|
||||||
list($connection, $event, $sql, $time, , $source) = $ticket;
|
|
||||||
|
|
||||||
dibi::$elapsedTime = $time;
|
|
||||||
dibi::$totalTime += $time;
|
|
||||||
|
|
||||||
if (($event & $this->filter) === 0) return;
|
|
||||||
|
|
||||||
if ($event & self::QUERY) {
|
|
||||||
try {
|
|
||||||
$ticket[4] = $count = $res instanceof DibiResult ? count($res) : '-';
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$count = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count(self::$fireTable) < self::$maxQueries) {
|
|
||||||
self::$fireTable[] = array(
|
|
||||||
sprintf('%0.3f', $time * 1000),
|
|
||||||
strlen($sql) > self::$maxLength ? substr($sql, 0, self::$maxLength) . '...' : $sql,
|
|
||||||
$count,
|
|
||||||
$connection->getConfig('driver') . '/' . $connection->getConfig('name')
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($this->useFirebug && !headers_sent()) {
|
|
||||||
header('X-Wf-Protocol-dibi: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
|
|
||||||
header('X-Wf-dibi-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');
|
|
||||||
header('X-Wf-dibi-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
|
|
||||||
|
|
||||||
$payload = json_encode(array(
|
|
||||||
array(
|
|
||||||
'Type' => 'TABLE',
|
|
||||||
'Label' => 'dibi profiler (' . dibi::$numOfQueries . ' SQL queries took ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms)',
|
|
||||||
),
|
|
||||||
self::$fireTable,
|
|
||||||
));
|
|
||||||
foreach (str_split($payload, 4990) as $num => $s) {
|
|
||||||
$num++;
|
|
||||||
header("X-Wf-dibi-1-1-d$num: |$s|\\"); // protocol-, structure-, plugin-, message-index
|
|
||||||
}
|
|
||||||
header("X-Wf-dibi-1-1-d$num: |$s|");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->file) {
|
|
||||||
$this->writeFile(
|
|
||||||
"OK: " . $sql
|
|
||||||
. ($res instanceof DibiResult ? ";\n-- rows: " . $count : '')
|
|
||||||
. "\n-- takes: " . sprintf('%0.3f', $time * 1000) . ' ms'
|
|
||||||
. "\n-- source: " . implode(':', $source)
|
|
||||||
. "\n-- driver: " . $connection->getConfig('driver') . '/' . $connection->getConfig('name')
|
|
||||||
. "\n-- " . date('Y-m-d H:i:s')
|
|
||||||
. "\n\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After exception notification.
|
|
||||||
* @param DibiDriverException
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function exception(DibiDriverException $exception)
|
|
||||||
{
|
|
||||||
if ((self::EXCEPTION & $this->filter) === 0) return;
|
|
||||||
|
|
||||||
if ($this->useFirebug) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->file) {
|
|
||||||
$message = $exception->getMessage();
|
|
||||||
$code = $exception->getCode();
|
|
||||||
if ($code) {
|
|
||||||
$message = "[$code] $message";
|
|
||||||
}
|
|
||||||
$this->writeFile(
|
|
||||||
"ERROR: $message"
|
|
||||||
. "\n-- SQL: " . dibi::$sql
|
|
||||||
. "\n-- driver: " //. $connection->getConfig('driver')
|
|
||||||
. ";\n-- " . date('Y-m-d H:i:s')
|
|
||||||
. "\n\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private function writeFile($message)
|
|
||||||
{
|
|
||||||
$handle = fopen($this->file, 'a');
|
|
||||||
if (!$handle) return; // or throw exception?
|
|
||||||
flock($handle, LOCK_EX);
|
|
||||||
fwrite($handle, $message);
|
|
||||||
fclose($handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************* interface Nette\Diagnostics\IBarPanel ****************d*g**/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns HTML code for custom tab.
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getTab()
|
|
||||||
{
|
|
||||||
return '<span title="dibi profiler"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
|
|
||||||
. dibi::$numOfQueries . ' queries</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns HTML code for custom panel.
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getPanel()
|
|
||||||
{
|
|
||||||
$s = NULL;
|
|
||||||
$h = 'htmlSpecialChars';
|
|
||||||
foreach (self::$tickets as $i => $ticket) {
|
|
||||||
list($connection, $event, $sql, $time, $count, $source) = $ticket;
|
|
||||||
if (!($event & self::QUERY)) continue;
|
|
||||||
|
|
||||||
$explain = NULL; // EXPLAIN is called here to work SELECT FOUND_ROWS()
|
|
||||||
if ($this->explainQuery && $event === self::SELECT) {
|
|
||||||
try {
|
|
||||||
$explain = dibi::dump($connection->setProfiler(NULL)->nativeQuery('EXPLAIN ' . $sql), TRUE);
|
|
||||||
} catch (DibiException $e) {}
|
|
||||||
$connection->setProfiler($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
$s .= '<tr><td>' . sprintf('%0.3f', $time * 1000);
|
|
||||||
if ($explain) {
|
|
||||||
$s .= "<br /><a href='#' class='nette-toggler' rel='#nette-debug-DibiProfiler-row-$i'>explain ►</a>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$s .= '</td><td class="nette-DibiProfiler-sql">' . dibi::dump(strlen($sql) > self::$maxLength ? substr($sql, 0, self::$maxLength) . '...' : $sql, TRUE);
|
|
||||||
if ($explain) {
|
|
||||||
$s .= "<div id='nette-debug-DibiProfiler-row-$i' class='nette-collapsed'>{$explain}</div>";
|
|
||||||
}
|
|
||||||
if ($source) {
|
|
||||||
list($file, $line) = $source;
|
|
||||||
$s .= "<span class='nette-DibiProfiler-source' title='{$h($file)}:$line'>{$h(basename(dirname($file)) . '/' . basename($file))}:$line</span>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$s .= "</td><td>{$count}</td><td>{$h($connection->getConfig('driver') . '/' . $connection->getConfig('name'))}</td></tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $s === NULL ? '' :
|
|
||||||
'<style> #nette-debug td.nette-DibiProfiler-sql { background: white !important }
|
|
||||||
#nette-debug .nette-DibiProfiler-source { color: #999 !important }
|
|
||||||
#nette-debug nette-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
|
|
||||||
<h1>Queries: ' . dibi::$numOfQueries . (dibi::$totalTime === NULL ? '' : ', time: ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms') . '</h1>
|
|
||||||
<div class="nette-inner nette-DibiProfiler">
|
|
||||||
<table>
|
|
||||||
<tr><th>Time ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '
|
|
||||||
</table>
|
|
||||||
</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -36,55 +36,6 @@ interface IDibiVariable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines method that must profiler implement.
|
|
||||||
*/
|
|
||||||
interface IDibiProfiler
|
|
||||||
{
|
|
||||||
/** event type */
|
|
||||||
const CONNECT = 1,
|
|
||||||
SELECT = 4,
|
|
||||||
INSERT = 8,
|
|
||||||
DELETE = 16,
|
|
||||||
UPDATE = 32,
|
|
||||||
QUERY = 60, // SELECT | INSERT | DELETE | UPDATE
|
|
||||||
BEGIN = 64,
|
|
||||||
COMMIT = 128,
|
|
||||||
ROLLBACK = 256,
|
|
||||||
TRANSACTION = 448, // BEGIN | COMMIT | ROLLBACK
|
|
||||||
EXCEPTION = 512,
|
|
||||||
ALL = 1023;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before event notification.
|
|
||||||
* @param DibiConnection
|
|
||||||
* @param int event name
|
|
||||||
* @param string sql
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
function before(DibiConnection $connection, $event, $sql = NULL);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After event notification.
|
|
||||||
* @param int
|
|
||||||
* @param DibiResult
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function after($ticket, $result = NULL);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After exception notification.
|
|
||||||
* @param DibiDriverException
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function exception(DibiDriverException $exception);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dibi driver interface.
|
* dibi driver interface.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,14 +13,14 @@ date_default_timezone_set('Europe/Prague');
|
|||||||
dibi::connect(array(
|
dibi::connect(array(
|
||||||
'driver' => 'sqlite',
|
'driver' => 'sqlite',
|
||||||
'database' => 'data/sample.sdb',
|
'database' => 'data/sample.sdb',
|
||||||
'profiler' => TRUE,
|
// enable query logging to this file
|
||||||
|
'profiler' => array(
|
||||||
|
'run' => TRUE,
|
||||||
|
'file' => 'data/log.sql',
|
||||||
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
// enable query logging to this file
|
|
||||||
dibi::getProfiler()->setFile('data/log.sql');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = %i', 1);
|
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = %i', 1);
|
||||||
|
Reference in New Issue
Block a user