mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-20 10:27:18 +08:00
debug toolbar WIP
This commit is contained in:
@ -16,32 +16,34 @@ use yii\log\Target;
|
|||||||
*/
|
*/
|
||||||
class LogTarget extends Target
|
class LogTarget extends Target
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
public $maxLogFiles = 20;
|
public $maxLogFiles = 20;
|
||||||
|
|
||||||
|
public function __construct($module, $config = array())
|
||||||
|
{
|
||||||
|
parent::__construct($config);
|
||||||
|
$this->module = $module;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports log messages to a specific destination.
|
* Exports log messages to a specific destination.
|
||||||
* Child classes must implement this method.
|
* Child classes must implement this method.
|
||||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
|
|
||||||
* of each message.
|
|
||||||
*/
|
*/
|
||||||
public function export($messages)
|
public function export()
|
||||||
{
|
{
|
||||||
$path = Yii::$app->getRuntimePath() . '/debug';
|
$path = Yii::$app->getRuntimePath() . '/debug';
|
||||||
if (!is_dir($path)) {
|
if (!is_dir($path)) {
|
||||||
mkdir($path);
|
mkdir($path);
|
||||||
}
|
}
|
||||||
$file = $path . '/' . Yii::$app->getLog()->getTag() . '.log';
|
$tag = Yii::$app->getLog()->getTag();
|
||||||
$data = array(
|
$file = "$path/$tag.log";
|
||||||
'messages' => $messages,
|
$data = array();
|
||||||
'_SERVER' => $_SERVER,
|
foreach ($this->module->panels as $panel) {
|
||||||
'_GET' => $_GET,
|
$data[$panel->id] = $panel->save();
|
||||||
'_POST' => $_POST,
|
}
|
||||||
'_COOKIE' => $_COOKIE,
|
|
||||||
'_FILES' => empty($_FILES) ? array() : $_FILES,
|
|
||||||
'_SESSION' => empty($_SESSION) ? array() : $_SESSION,
|
|
||||||
'memory' => memory_get_peak_usage(),
|
|
||||||
'time' => microtime(true) - YII_BEGIN_TIME,
|
|
||||||
);
|
|
||||||
file_put_contents($file, json_encode($data));
|
file_put_contents($file, json_encode($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,19 +18,28 @@ use yii\helpers\Html;
|
|||||||
class Module extends \yii\base\Module
|
class Module extends \yii\base\Module
|
||||||
{
|
{
|
||||||
public $controllerNamespace = 'yii\debug\controllers';
|
public $controllerNamespace = 'yii\debug\controllers';
|
||||||
public $panels;
|
/**
|
||||||
|
* @var array|Panel[]
|
||||||
|
*/
|
||||||
|
public $panels = array();
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
parent::init();
|
parent::init();
|
||||||
Yii::$app->log->targets['debug'] = new LogTarget;
|
|
||||||
|
foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) {
|
||||||
|
$config['id'] = $id;
|
||||||
|
$this->panels[$id] = Yii::createObject($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
Yii::$app->getLog()->targets['debug'] = new LogTarget($this);
|
||||||
Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar'));
|
Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function beforeAction($action)
|
public function beforeAction($action)
|
||||||
{
|
{
|
||||||
Yii::$app->getView()->off(View::EVENT_END_BODY, array($this, 'renderToolbar'));
|
Yii::$app->getView()->off(View::EVENT_END_BODY, array($this, 'renderToolbar'));
|
||||||
unset(Yii::$app->log->targets['debug']);
|
unset(Yii::$app->getLog()->targets['debug']);
|
||||||
return parent::beforeAction($action);
|
return parent::beforeAction($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,4 +58,19 @@ class Module extends \yii\base\Module
|
|||||||
'style' => 'display: none',
|
'style' => 'display: none',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function corePanels()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'config' => array(
|
||||||
|
'class' => 'yii\debug\panels\ConfigPanel',
|
||||||
|
),
|
||||||
|
'request' => array(
|
||||||
|
'class' => 'yii\debug\panels\RequestPanel',
|
||||||
|
),
|
||||||
|
'log' => array(
|
||||||
|
'class' => 'yii\debug\panels\LogPanel',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
45
framework/yii/debug/Panel.php
Normal file
45
framework/yii/debug/Panel.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\debug;
|
||||||
|
|
||||||
|
use yii\base\Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class Panel extends Component
|
||||||
|
{
|
||||||
|
public $id;
|
||||||
|
public $data;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummary()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ namespace yii\debug\controllers;
|
|||||||
|
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\web\Controller;
|
use yii\web\Controller;
|
||||||
|
use yii\web\HttpException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
@ -16,22 +17,48 @@ use yii\web\Controller;
|
|||||||
*/
|
*/
|
||||||
class DefaultController extends Controller
|
class DefaultController extends Controller
|
||||||
{
|
{
|
||||||
|
/** @var \yii\debug\Module */
|
||||||
|
public $module;
|
||||||
public $layout = 'main';
|
public $layout = 'main';
|
||||||
|
|
||||||
public function actionIndex($tag)
|
public function actionIndex($tag, $panel = null)
|
||||||
{
|
{
|
||||||
return $this->render('index');
|
$this->loadData($tag);
|
||||||
|
if (isset($this->module->panels[$panel])) {
|
||||||
|
$activePanel = $this->module->panels[$panel];
|
||||||
|
} else {
|
||||||
|
$activePanel = reset($this->module->panels);
|
||||||
|
}
|
||||||
|
return $this->render('index', array(
|
||||||
|
'tag' => $tag,
|
||||||
|
'panels' => $this->module->panels,
|
||||||
|
'activePanel' => $activePanel,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function actionToolbar($tag)
|
public function actionToolbar($tag)
|
||||||
|
{
|
||||||
|
$this->loadData($tag);
|
||||||
|
return $this->renderPartial('toolbar', array(
|
||||||
|
'panels' => $this->module->panels,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadData($tag)
|
||||||
{
|
{
|
||||||
$file = Yii::$app->getRuntimePath() . "/debug/$tag.log";
|
$file = Yii::$app->getRuntimePath() . "/debug/$tag.log";
|
||||||
if (preg_match('/^[\w\-]+$/', $tag) && is_file($file)) {
|
if (preg_match('/^[\w\-]+$/', $tag) && is_file($file)) {
|
||||||
$data = json_decode(file_get_contents($file), true);
|
$data = json_decode(file_get_contents($file), true);
|
||||||
$data['tag'] = $tag;
|
foreach ($this->module->panels as $id => $panel) {
|
||||||
return $this->renderPartial('toolbar', $data);
|
if (isset($data[$panel->id])) {
|
||||||
|
$panel->load($data[$panel->id]);
|
||||||
} else {
|
} else {
|
||||||
return "Unable to find debug data tagged with '$tag'.";
|
// remove the panel since it has not received any data
|
||||||
|
unset($this->module->panels[$id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new HttpException(404, "Unable to find debug data tagged with '$tag'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
framework/yii/debug/panels/ConfigPanel.php
Normal file
50
framework/yii/debug/panels/ConfigPanel.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\debug\panels;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use yii\debug\Panel;
|
||||||
|
use yii\helpers\Html;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class ConfigPanel extends Panel
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Config';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummary()
|
||||||
|
{
|
||||||
|
$link = Html::a('more details', array('index', 'tag' => $this->data['tag']));
|
||||||
|
return <<<EOD
|
||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
PHP: {$this->data['phpVersion']},
|
||||||
|
Yii: {$this->data['phpVersion']},
|
||||||
|
$link
|
||||||
|
</div>
|
||||||
|
EOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
return '<h2>Config</h2>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'tag' => Yii::$app->getLog()->getTag(),
|
||||||
|
'phpVersion' => PHP_VERSION,
|
||||||
|
'yiiVersion' => Yii::getVersion(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
45
framework/yii/debug/panels/LogPanel.php
Normal file
45
framework/yii/debug/panels/LogPanel.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\debug\panels;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use yii\debug\Panel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class LogPanel extends Panel
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Logs';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummary()
|
||||||
|
{
|
||||||
|
$count = count($this->data['messages']);
|
||||||
|
return <<<EOD
|
||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
Log messages: $count
|
||||||
|
</div>
|
||||||
|
EOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
return '<h2>Logs</h2>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'messages' => Yii::$app->getLog()->targets['debug']->messages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
57
framework/yii/debug/panels/RequestPanel.php
Normal file
57
framework/yii/debug/panels/RequestPanel.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\debug\panels;
|
||||||
|
|
||||||
|
use yii\debug\Panel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class RequestPanel extends Panel
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Request';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummary()
|
||||||
|
{
|
||||||
|
$memory = sprintf('%.2fMB', $this->data['memory'] / 1048576);
|
||||||
|
$time = sprintf('%.3fs', $this->data['time']);
|
||||||
|
|
||||||
|
return <<<EOD
|
||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
Peak memory: $memory
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
Time spent: $time
|
||||||
|
</div>
|
||||||
|
EOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
return '<h2>Request</h2>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'memory' => memory_get_peak_usage(),
|
||||||
|
'time' => microtime(true) - YII_BEGIN_TIME,
|
||||||
|
'SERVER' => $_SERVER,
|
||||||
|
'GET' => $_GET,
|
||||||
|
'POST' => $_POST,
|
||||||
|
'COOKIE' => $_COOKIE,
|
||||||
|
'FILES' => empty($_FILES) ? array() : $_FILES,
|
||||||
|
'SESSION' => empty($_SESSION) ? array() : $_SESSION,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,16 @@
|
|||||||
here we are
|
<?php
|
||||||
|
|
||||||
|
use yii\helpers\Html;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \yii\base\View $this
|
||||||
|
* @var string $tag
|
||||||
|
* @var \yii\debug\Panel[] $panels
|
||||||
|
* @var \yii\debug\Panel $activePanel
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<?php foreach ($panels as $panel): ?>
|
||||||
|
<?php echo Html::a(Html::encode($panel->getName()), array('debug/default/index', 'tag' => $tag, 'panel' => $panel->id)); ?><br>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php echo $activePanel->getDetail(); ?>
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<?php use yii\helpers\Html;
|
<?php
|
||||||
|
/**
|
||||||
echo Html::style("
|
* @var \yii\base\View $this
|
||||||
|
* @var \yii\debug\Panel[] $panels
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
#yii-debug-toolbar {
|
#yii-debug-toolbar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -17,24 +21,11 @@ echo Html::style("
|
|||||||
.yii-debug-toolbar-block {
|
.yii-debug-toolbar-block {
|
||||||
float: left;
|
float: left;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
");
|
}
|
||||||
?>
|
</style>
|
||||||
|
|
||||||
<div id="yii-debug-toolbar">
|
<div id="yii-debug-toolbar">
|
||||||
<div class="yii-debug-toolbar-block">
|
<?php foreach ($panels as $panel): ?>
|
||||||
<?php echo Html::a('more details', array('index', 'tag' => $tag)); ?>
|
<?php echo $panel->getSummary(); ?>
|
||||||
</div>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
Peak memory: <?php echo sprintf('%.2fMB', $memory / 1048576); ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
Time spent: <?php echo sprintf('%.3fs', $time); ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,16 +72,14 @@ class DbTarget extends Target
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores log messages to DB.
|
* Stores log messages to DB.
|
||||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
|
|
||||||
* of each message.
|
|
||||||
*/
|
*/
|
||||||
public function export($messages)
|
public function export()
|
||||||
{
|
{
|
||||||
$tableName = $this->db->quoteTableName($this->logTable);
|
$tableName = $this->db->quoteTableName($this->logTable);
|
||||||
$sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[message]])
|
$sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[message]])
|
||||||
VALUES (:level, :category, :log_time, :message)";
|
VALUES (:level, :category, :log_time, :message)";
|
||||||
$command = $this->db->createCommand($sql);
|
$command = $this->db->createCommand($sql);
|
||||||
foreach ($messages as $message) {
|
foreach ($this->messages as $message) {
|
||||||
$command->bindValues(array(
|
$command->bindValues(array(
|
||||||
':level' => $message[1],
|
':level' => $message[1],
|
||||||
':category' => $message[2],
|
':category' => $message[2],
|
||||||
|
@ -38,13 +38,11 @@ class EmailTarget extends Target
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends log messages to specified email addresses.
|
* Sends log messages to specified email addresses.
|
||||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
|
|
||||||
* of each message.
|
|
||||||
*/
|
*/
|
||||||
public function export($messages)
|
public function export()
|
||||||
{
|
{
|
||||||
$body = '';
|
$body = '';
|
||||||
foreach ($messages as $message) {
|
foreach ($this->messages as $message) {
|
||||||
$body .= $this->formatMessage($message);
|
$body .= $this->formatMessage($message);
|
||||||
}
|
}
|
||||||
$body = wordwrap($body, 70);
|
$body = wordwrap($body, 70);
|
||||||
|
@ -65,14 +65,12 @@ class FileTarget extends Target
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends log messages to specified email addresses.
|
* Sends log messages to specified email addresses.
|
||||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
|
|
||||||
* of each message.
|
|
||||||
* @throws InvalidConfigException if unable to open the log file for writing
|
* @throws InvalidConfigException if unable to open the log file for writing
|
||||||
*/
|
*/
|
||||||
public function export($messages)
|
public function export()
|
||||||
{
|
{
|
||||||
$text = '';
|
$text = '';
|
||||||
foreach ($messages as $message) {
|
foreach ($this->messages as $message) {
|
||||||
$text .= $this->formatMessage($message);
|
$text .= $this->formatMessage($message);
|
||||||
}
|
}
|
||||||
if (($fp = @fopen($this->logFile, 'a')) === false) {
|
if (($fp = @fopen($this->logFile, 'a')) === false) {
|
||||||
|
@ -124,7 +124,7 @@ class Logger extends Component
|
|||||||
*/
|
*/
|
||||||
public $messages = array();
|
public $messages = array();
|
||||||
/**
|
/**
|
||||||
* @var array the log targets. Each array element represents a single [[Target|log target]] instance
|
* @var array|Target[] the log targets. Each array element represents a single [[Target|log target]] instance
|
||||||
* or the configuration for creating the log target instance.
|
* or the configuration for creating the log target instance.
|
||||||
*/
|
*/
|
||||||
public $targets = array();
|
public $targets = array();
|
||||||
|
@ -68,18 +68,17 @@ abstract class Target extends Component
|
|||||||
public $exportInterval = 1000;
|
public $exportInterval = 1000;
|
||||||
/**
|
/**
|
||||||
* @var array the messages that are retrieved from the logger so far by this log target.
|
* @var array the messages that are retrieved from the logger so far by this log target.
|
||||||
|
* Please refer to [[Logger::messages]] for the details about the message structure.
|
||||||
*/
|
*/
|
||||||
public $messages = array();
|
public $messages = array();
|
||||||
|
|
||||||
private $_levels = 0;
|
private $_levels = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports log messages to a specific destination.
|
* Exports log [[messages]] to a specific destination.
|
||||||
* Child classes must implement this method.
|
* Child classes must implement this method.
|
||||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
|
|
||||||
* of each message.
|
|
||||||
*/
|
*/
|
||||||
abstract public function export($messages);
|
abstract public function export();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the given log messages.
|
* Processes the given log messages.
|
||||||
@ -97,7 +96,7 @@ abstract class Target extends Component
|
|||||||
if (($context = $this->getContextMessage()) !== '') {
|
if (($context = $this->getContextMessage()) !== '') {
|
||||||
$this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
|
$this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
|
||||||
}
|
}
|
||||||
$this->export($this->messages);
|
$this->export();
|
||||||
$this->messages = array();
|
$this->messages = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user