From d5bc3c703307b79206580d1f0d7d3f4359e0aaac Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 30 Dec 2013 08:09:25 +0400 Subject: [PATCH] improved database panel in debug module --- .../yii/debug/components/search/matches/Exact.php | 2 +- extensions/yii/debug/models/search/Db.php | 75 ++++++++++++ extensions/yii/debug/panels/DbPanel.php | 134 +++++++++++++-------- extensions/yii/debug/panels/LogPanel.php | 2 +- .../yii/debug/views/default/panels/db/detail.php | 53 ++++++++ .../yii/debug/views/default/panels/db/summary.php | 7 ++ 6 files changed, 219 insertions(+), 54 deletions(-) create mode 100644 extensions/yii/debug/models/search/Db.php create mode 100644 extensions/yii/debug/views/default/panels/db/detail.php create mode 100644 extensions/yii/debug/views/default/panels/db/summary.php diff --git a/extensions/yii/debug/components/search/matches/Exact.php b/extensions/yii/debug/components/search/matches/Exact.php index 34bb0cd..5fe6eec 100644 --- a/extensions/yii/debug/components/search/matches/Exact.php +++ b/extensions/yii/debug/components/search/matches/Exact.php @@ -29,7 +29,7 @@ class Exact extends Base if (!$this->partial) { return (mb_strtolower($this->value, 'utf8') == mb_strtolower($value, 'utf8')); } else { - return (mb_strpos($value, $this->value) !== false); + return (mb_strpos(mb_strtolower($value, 'utf8'), mb_strtolower($this->value,'utf8')) !== false); } } diff --git a/extensions/yii/debug/models/search/Db.php b/extensions/yii/debug/models/search/Db.php new file mode 100644 index 0000000..c5592fe --- /dev/null +++ b/extensions/yii/debug/models/search/Db.php @@ -0,0 +1,75 @@ + 'Type', + 'query' => 'Query', + ]; + } + + /** + * Returns data provider with filled models. Filter applied if needed. + * @param array $params + * @param array $models + * @return \yii\data\ArrayDataProvider + */ + public function search($params, $models) + { + $dataProvider = new ArrayDataProvider([ + 'allModels' => $models, + 'pagination' => [ + 'pageSize' => 10, + ], + 'sort' => [ + 'attributes' => ['duration','type','query'], + 'defaultOrder' => [ + 'duration' => SORT_DESC, + ], + ], + ]); + + if (!($this->load($params) && $this->validate())) { + return $dataProvider; + } + + $filter = new Filter(); + $this->addCondition($filter, 'type', true); + $this->addCondition($filter, 'query', true); + $dataProvider->allModels = $filter->filter($models); + + return $dataProvider; + } + +} diff --git a/extensions/yii/debug/panels/DbPanel.php b/extensions/yii/debug/panels/DbPanel.php index bc79072..ebac11f 100644 --- a/extensions/yii/debug/panels/DbPanel.php +++ b/extensions/yii/debug/panels/DbPanel.php @@ -7,10 +7,10 @@ namespace yii\debug\panels; +use Yii; use yii\debug\Panel; -use yii\helpers\ArrayHelper; use yii\log\Logger; -use yii\helpers\Html; +use yii\debug\models\search\Db; /** * Debugger panel that collects and displays database queries performed. @@ -20,6 +20,17 @@ use yii\helpers\Html; */ class DbPanel extends Panel { + + /** + * @var array db queries info extracted to array as models, to use with data provider. + */ + private $_models; + + /** + * @var array current database request timings + */ + private $_timings; + public function getName() { return 'Database'; @@ -29,61 +40,27 @@ class DbPanel extends Panel { $timings = $this->calculateTimings(); $queryCount = count($timings); - $queryTime = 0; - foreach ($timings as $timing) { - $queryTime += $timing[3]; - } - $queryTime = number_format($queryTime * 1000) . ' ms'; - $url = $this->getUrl(); - $output = << - - DB $queryCount $queryTime - - -EOD; - return $queryCount > 0 ? $output : ''; + $queryTime = number_format($this->getTotalQueryTime($timings) * 1000) . ' ms'; + + return Yii::$app->view->render('panels/db/summary',[ + 'timings' => $this->calculateTimings(), + 'panel' => $this, + 'queryCount' => $queryCount, + 'queryTime' => $queryTime, + ]); } public function getDetail() { - $timings = $this->calculateTimings(); - ArrayHelper::multisort($timings, 3, SORT_DESC); - $rows = []; - foreach ($timings as $timing) { - $duration = sprintf('%.1f ms', $timing[3] * 1000); - $procedure = Html::encode($timing[1]); - $traces = $timing[4]; - if (!empty($traces)) { - $procedure .= Html::ul($traces, [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']}({$trace['line']})
  • "; - }, - ]); - } - $rows[] = "$duration$procedure"; - } - $rows = implode("\n", $rows); - - return <<Database Queries - - - - - - - - - -$rows - -
    TimeQuery
    -EOD; - } + $searchModel = new Db(); + $dataProvider = $searchModel->search($_GET, $this->getModels()); - private $_timings; + return Yii::$app->view->render('panels/db/detail',[ + 'panel' => $this, + 'dataProvider' => $dataProvider, + 'searchModel' => $searchModel, + ]); + } protected function calculateTimings() { @@ -120,4 +97,57 @@ EOD; $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE, ['yii\db\Command::query', 'yii\db\Command::execute']); return ['messages' => $messages]; } + + /** + * Returns total queries time. + * @param array $timings + * @return integer total time + */ + protected function getTotalQueryTime($timings) + { + $queryTime = 0; + + foreach ($timings as $timing) { + $queryTime += $timing[3]; + } + + return $queryTime; + } + + /** + * Returns array of models that represents logs of the current request. Can be used with data providers, + * like yii\data\ArrayDataProvider. + * @return array models + */ + protected function getModels() + { + if ($this->_models === null || $refresh) { + $this->_models = []; + $timings = $this->calculateTimings(); + + foreach($timings as $dbTiming) { + $this->_models[] = [ + 'type' => $this->detectQueryType($dbTiming[1]), + 'query' => $dbTiming[1], + 'duration' => ($dbTiming[3] * 1000), #in milliseconds + 'trace' => $dbTiming[4], + ]; + } + } + return $this->_models; + } + + /** + * Detects databse timing type. Detecting is produced through simple parsing to the first space|tab|new row. + * First word before space is timing type. If there is no such words, timing will have empty type. + * @param string $timing timing procedure string + * @return string query type select|insert|delete|etc + */ + protected function detectQueryType($timing) + { + $timing = ltrim($timing); + preg_match('/^([a-zA-z]*)/', $timing, $matches); + return count($matches) ? $matches[0] : ''; + } + } diff --git a/extensions/yii/debug/panels/LogPanel.php b/extensions/yii/debug/panels/LogPanel.php index e80f2d8..427fb54 100644 --- a/extensions/yii/debug/panels/LogPanel.php +++ b/extensions/yii/debug/panels/LogPanel.php @@ -24,7 +24,7 @@ class LogPanel extends Panel /** * @var array log messages extracted to array as models, to use with data provider. */ - private $_models ; + private $_models; public function getName() { diff --git a/extensions/yii/debug/views/default/panels/db/detail.php b/extensions/yii/debug/views/default/panels/db/detail.php new file mode 100644 index 0000000..218bdf4 --- /dev/null +++ b/extensions/yii/debug/views/default/panels/db/detail.php @@ -0,0 +1,53 @@ + +

    Database Queries

    + + $dataProvider, + 'id' => 'db-panel-detailed-grid', + 'filterModel' => $searchModel, + 'filterUrl' => $panel->getUrl(), + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + [ + 'attribute' => 'duration', + 'value' => function ($data) + { + return sprintf('%.1f ms',$data['duration']); + }, + ], + [ + 'attribute' => 'type', + 'value' => function ($data) + { + return Html::encode(mb_strtoupper($data['type'],'utf8')); + }, + ], + [ + 'attribute' => 'query', + 'value' => function ($data) + { + $query = Html::encode($data['query']); + + if (!empty($data['trace'])) { + $query .= Html::ul($data['trace'], [ + 'class' => 'trace', + 'item' => function ($trace) { + return "
  • {$trace['file']}({$trace['line']})
  • "; + }, + ]); + } + return $query; + }, + 'format' => 'html', + 'options' => [ + 'width' => '70%', + ], + ] + ], +]); +?> \ No newline at end of file diff --git a/extensions/yii/debug/views/default/panels/db/summary.php b/extensions/yii/debug/views/default/panels/db/summary.php new file mode 100644 index 0000000..1c3bdfa --- /dev/null +++ b/extensions/yii/debug/views/default/panels/db/summary.php @@ -0,0 +1,7 @@ + + + \ No newline at end of file