diff --git a/extensions/yii/debug/LogTarget.php b/extensions/yii/debug/LogTarget.php index 4b75cfa..1359b36 100644 --- a/extensions/yii/debug/LogTarget.php +++ b/extensions/yii/debug/LogTarget.php @@ -52,6 +52,7 @@ class LogTarget extends Target $manifest = unserialize(file_get_contents($indexFile)); } $request = Yii::$app->getRequest(); + $response = Yii::$app->getResponse(); $manifest[$this->tag] = $summary = [ 'tag' => $this->tag, 'url' => $request->getAbsoluteUrl(), @@ -59,6 +60,8 @@ class LogTarget extends Target 'method' => $request->getMethod(), 'ip' => $request->getUserIP(), 'time' => time(), + 'statusCode' => $response->statusCode, + 'sqlCount' => $this->getSqlTotalCount(), ]; $this->gc($manifest); @@ -102,4 +105,21 @@ class LogTarget extends Target } } } + + /** + * Returns total sql count executed in current request. If database panel is not configured + * returns 0. + * @return integer + */ + protected function getSqlTotalCount() + { + if (!isset($this->module->panels['db'])) { + return 0; + } + $profileLogs = $this->module->panels['db']->save(); + + # / 2 because messages are in couple (begin/end) + return count($profileLogs['messages']) / 2; + } + } diff --git a/extensions/yii/debug/components/search/Filter.php b/extensions/yii/debug/components/search/Filter.php new file mode 100644 index 0000000..85c30ee --- /dev/null +++ b/extensions/yii/debug/components/search/Filter.php @@ -0,0 +1,75 @@ + [rule1, rule2,..]] + */ + protected $rules = []; + + /** + * Adds rules for filtering data. Match can be partial or exactly. + * @param string $name attribute name + * @param \yii\debug\components\search\matches\Base $rule + */ + public function addMatch($name, $rule) + { + if (empty($rule->value) && $rule->value !== 0) { + return; + } + + $this->rules[$name][] = $rule; + } + + /** + * Applies filter on given array and returns filtered data. + * @param array $data data to filter + * @return array filtered data + */ + public function filter(array $data) + { + $filtered = []; + + foreach($data as $row) + { + if ($this->checkFilter($row)) { + $filtered[] = $row; + } + } + + return $filtered; + } + + /** + * Check if the given data satisfies filters. + * @param array $row + */ + public function checkFilter(array $row) + { + $matched = true; + + foreach ($row as $name=>$value) + { + if (isset($this->rules[$name])) { + + #check all rules for given attribute + + foreach($this->rules[$name] as $rule) + { + if (!$rule->check($value)) { + $matched = false; + } + } + + } + } + + return $matched; + } + +} diff --git a/extensions/yii/debug/components/search/matches/Base.php b/extensions/yii/debug/components/search/matches/Base.php new file mode 100644 index 0000000..6d8250d --- /dev/null +++ b/extensions/yii/debug/components/search/matches/Base.php @@ -0,0 +1,26 @@ + + * @since 2.0 + */ +abstract class Base extends Component implements MatcherInterface +{ + + /** + * @var mixed current value to check for the matcher + */ + public $value; + +} diff --git a/extensions/yii/debug/components/search/matches/Exact.php b/extensions/yii/debug/components/search/matches/Exact.php new file mode 100644 index 0000000..40a9bcc --- /dev/null +++ b/extensions/yii/debug/components/search/matches/Exact.php @@ -0,0 +1,36 @@ + + * @since 2.0 + */ +class Exact extends Base +{ + + /** + * @var boolean if current matcher should consider partial mathc of given value. + */ + public $partial = false; + + /** + * Checks if the given value is the same as base one or has partial match with base one. + * @param mixed $value + */ + public function check($value) + { + if (!$this->partial) { + return (mb_strtolower($this->value,'utf8') == mb_strtolower($value,'utf8')); + } else { + return (mb_strpos($value, $this->value) !== false); + } + } + +} diff --git a/extensions/yii/debug/components/search/matches/Greater.php b/extensions/yii/debug/components/search/matches/Greater.php new file mode 100644 index 0000000..e475dc7 --- /dev/null +++ b/extensions/yii/debug/components/search/matches/Greater.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class Greater extends Base +{ + + /** + * Checks if the given value is the same as base one or has partial match with base one. + * @param mixed $value + */ + public function check($value) + { + return ($value > $this->value); + } + +} diff --git a/extensions/yii/debug/components/search/matches/Lower.php b/extensions/yii/debug/components/search/matches/Lower.php new file mode 100644 index 0000000..9222fd7 --- /dev/null +++ b/extensions/yii/debug/components/search/matches/Lower.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class Lower extends Base +{ + + /** + * Checks if the given value is the same as base one or has partial match with base one. + * @param mixed $value + */ + public function check($value) + { + return ($value < $this->value); + } + +} diff --git a/extensions/yii/debug/components/search/matches/MatcherInterface.php b/extensions/yii/debug/components/search/matches/MatcherInterface.php new file mode 100644 index 0000000..16c0705 --- /dev/null +++ b/extensions/yii/debug/components/search/matches/MatcherInterface.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +interface MatcherInterface +{ + + /** + * Check if the value is correct according current matcher. + * @param mixed $value + */ + public function check($value); + +} diff --git a/extensions/yii/debug/controllers/DefaultController.php b/extensions/yii/debug/controllers/DefaultController.php index 4d525f7..6109a39 100644 --- a/extensions/yii/debug/controllers/DefaultController.php +++ b/extensions/yii/debug/controllers/DefaultController.php @@ -10,6 +10,7 @@ namespace yii\debug\controllers; use Yii; use yii\web\Controller; use yii\web\NotFoundHttpException; +use yii\debug\models\search\Debug; /** * @author Qiang Xue @@ -38,7 +39,13 @@ class DefaultController extends Controller public function actionIndex() { - return $this->render('index', ['manifest' => $this->getManifest()]); + $searchModel = new Debug(); + $dataProvider = $searchModel->search($_GET, $this->getManifest()); + + return $this->render('index', [ + 'dataProvider' => $dataProvider, + 'searchModel' => $searchModel, + ]); } public function actionView($tag = null, $panel = null) diff --git a/extensions/yii/debug/models/search/Debug.php b/extensions/yii/debug/models/search/Debug.php new file mode 100644 index 0000000..27bed49 --- /dev/null +++ b/extensions/yii/debug/models/search/Debug.php @@ -0,0 +1,145 @@ + 'Tag', + 'ip' => 'Ip', + 'method' => 'Method', + 'ajax' => 'Ajax', + 'url' => 'url', + 'statusCode' => 'Status code', + 'sqlCount' => 'Total queries count', + ]; + } + + /** + * Returns data provider with filled models. Filter applied if needed. + * @param type $params + * @param type $models + * @return \yii\data\ArrayDataProvider + */ + public function search($params, $models) + { + $dataProvider = new ArrayDataProvider([ + 'allModels' => $models, + 'sort' => [ + 'attributes' => ['method', 'ip','tag','time','statusCode','sqlCount'], + ], + 'pagination' => [ + 'pageSize' => 10, + ], + ]); + + if (!($this->load($params) && $this->validate())) { + return $dataProvider; + } + + $filter = new Filter(); + $this->addCondition($filter, 'tag', true); + $this->addCondition($filter, 'ip', true); + $this->addCondition($filter, 'method'); + $this->addCondition($filter, 'ajax'); + $this->addCondition($filter, 'url', true); + $this->addCondition($filter, 'statusCode'); + $this->addCondition($filter, 'sqlCount'); + $dataProvider->allModels = $filter->filter($models); + + return $dataProvider; + } + + /** + * Checks if the code is critical: 400 or greater, 500 or greater. + * @param integer $code + * @return bool + */ + public function isCodeCritical($code) + { + return in_array($code, $this->criticalCodes); + } + + public function addCondition($filter,$attribute,$partial=false) + { + $value = $this->$attribute; + + if (mb_strpos($value, '>') !== false) + { + + $value = intval(str_replace('>', '', $value)); + $filter->addMatch($attribute,new matches\Greater(['value' => $value])); + + } elseif (mb_strpos($value, '<') !== false) { + + $value = intval(str_replace('<', '', $value)); + $filter->addMatch($attribute,new matches\Lower(['value' => $value])); + + } else { + $filter->addMatch($attribute,new matches\Exact(['value' => $value, 'partial' => $partial])); + } + + } + +} diff --git a/extensions/yii/debug/views/default/index.php b/extensions/yii/debug/views/default/index.php index 93737e2..9164205 100644 --- a/extensions/yii/debug/views/default/index.php +++ b/extensions/yii/debug/views/default/index.php @@ -1,6 +1,9 @@ title = 'Yii Debugger';

Available Debug Data

- - - - - - - - - - - - $data): ?> - - - - - - - - - -
TagTimeIPMethodURL
$tag]) ?>
+ + 'yii\i18n\Formatter']) : Yii::$app->formatter; + +echo GridView::widget([ + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'rowOptions' => function ($model, $key, $index, $grid) use ($searchModel) + { + if ($searchModel->isCodeCritical($model['statusCode'])) + return ['class'=>'danger']; + }, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + [ + 'attribute' => 'tag', + 'value' => function ($data) + { + return Html::a($data['tag'], ['view', 'tag' => $data['tag']]); + }, + 'format' => 'html', + ], + [ + 'attribute' => 'time', + 'value' => function ($data) use ($timeFormatter) + { + return $timeFormatter->asDateTime($data['time'], 'long'); + }, + ], + 'ip', + [ + 'attribute' => 'sqlCount', + 'label' => 'Total queries count' + ], + [ + 'attribute' => 'method', + 'filter' => ['get' => 'GET', 'post' => 'POST', 'delete' => 'DELETE', 'put' => 'PUT', 'head' => 'HEAD'] + ], + [ + 'attribute'=>'ajax', + 'value' => function ($data) + { + return $data['ajax'] ? 'Yes' : 'No'; + }, + 'filter' => ['No', 'Yes'], + ], + 'url', + [ + 'attribute' => 'statusCode', + 'filter' => [200=>200, 404=>404, 403=>403, 500=>500], + 'label' => 'Status code' + ], + ], +]); ?>