Miscellaneous cleanup
This commit is contained in:
parent
8c49715a55
commit
bd4e041e7d
18
index.php
18
index.php
@ -75,13 +75,23 @@ if( ! class_exists('pdo'))
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Convert Errors to Exceptions
|
||||
// Do this after the two compatibility checks for cleaner output
|
||||
/**
|
||||
* Error handler to convert errors to exceptions
|
||||
*
|
||||
* @param int $errno
|
||||
* @param string $errstr
|
||||
* @param string $errfile
|
||||
* @param int $errline
|
||||
* @throws ErrorException
|
||||
*/
|
||||
function exception_error_handler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
set_error_handler("exception_error_handler");
|
||||
|
||||
// Do this after the two compatibility checks for cleaner output
|
||||
// Note that this will throw exceptions on notices
|
||||
set_error_handler("exception_error_handler", -1);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@ -111,7 +121,7 @@ $path = BASE_DIR . "/db/drivers/";
|
||||
|
||||
foreach(pdo_drivers() as $d)
|
||||
{
|
||||
//Favor ibase over PDO firebird
|
||||
//Favor ibase/fbird over PDO firebird
|
||||
if ($d === 'firebird')
|
||||
{
|
||||
continue;
|
||||
|
@ -31,6 +31,10 @@ class MySQL extends DB_PDO {
|
||||
*/
|
||||
public function __construct($dsn, $username=null, $password=null, $options=array())
|
||||
{
|
||||
$options = array_merge($options, array(
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF-8 COLLATE 'UTF-8'",
|
||||
));
|
||||
|
||||
parent::__construct("mysql:$dsn", $username, $password, $options);
|
||||
|
||||
$class = __CLASS__.'_sql';
|
||||
|
@ -94,6 +94,7 @@ class Query_Builder {
|
||||
{
|
||||
$dsn .= ";port={$params->port}";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "sqlite":
|
||||
@ -105,6 +106,9 @@ class Query_Builder {
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the charset
|
||||
//$dsn .= ";charset=utf-8";
|
||||
|
||||
// Create the database connection
|
||||
if ( ! empty($params->user))
|
||||
{
|
||||
|
@ -48,17 +48,12 @@ class Connection_Sidebar extends GtkVBox {
|
||||
|
||||
$this->settings =& Settings::get_instance();
|
||||
|
||||
//$dblabel = new GtkLabel('Database Connections');
|
||||
//$dblabel->set_alignment(0,0);
|
||||
|
||||
$add_button = new GtkButton();
|
||||
$add_button->set_label("New Connnection");
|
||||
$add_button->set_image(GTKImage::new_from_stock(GTK::STOCK_ADD, Gtk::ICON_SIZE_SMALL_TOOLBAR));
|
||||
|
||||
$add_button->connect_simple('clicked', array($this, 'new_conn'));
|
||||
|
||||
//$this->pack_start($dblabel, FALSE, FALSE);
|
||||
|
||||
// Treeview to show database connections
|
||||
{
|
||||
// Render the treeview
|
||||
@ -80,6 +75,8 @@ class Connection_Sidebar extends GtkVBox {
|
||||
|
||||
/**
|
||||
* Renders the connection sidebar widget
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _render()
|
||||
{
|
||||
@ -138,6 +135,7 @@ class Connection_Sidebar extends GtkVBox {
|
||||
* @param GtkCellRenderer $cell
|
||||
* @param GtkTreeModel $this->model
|
||||
* @param GtkTreeIter $iter
|
||||
* @return void
|
||||
*/
|
||||
public function set_icon($col, $cell, $model, $iter)
|
||||
{
|
||||
@ -167,6 +165,7 @@ class Connection_Sidebar extends GtkVBox {
|
||||
* @param GtkCellRenderer $cell
|
||||
* @param GtkTreeModel $this->model
|
||||
* @param GtkTreeIter $iter
|
||||
* @return void
|
||||
*/
|
||||
public function set_label($col, $cell, $model, $iter)
|
||||
{
|
||||
@ -184,6 +183,7 @@ class Connection_Sidebar extends GtkVBox {
|
||||
* @param GtkCellRenderer $cell
|
||||
* @param GtkTreeModel $model
|
||||
* @param GtkTreeIter $iter
|
||||
* @return void
|
||||
*/
|
||||
public function set_status_icon($col, $cell, $model, $iter)
|
||||
{
|
||||
@ -311,6 +311,8 @@ class Connection_Sidebar extends GtkVBox {
|
||||
|
||||
/**
|
||||
* Recreate sidebar widget to update connections
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
@ -322,6 +324,8 @@ class Connection_Sidebar extends GtkVBox {
|
||||
|
||||
/**
|
||||
* Update the connection information for an existing connection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit_connection()
|
||||
{
|
||||
@ -382,13 +386,15 @@ class Connection_Sidebar extends GtkVBox {
|
||||
|
||||
/**
|
||||
* Disconnect from a database
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function db_disconnect()
|
||||
{
|
||||
$data = $this->treeview->get(0);
|
||||
|
||||
DB_Reg::remove_db($data->name);
|
||||
DB_Tabs::reset();
|
||||
DB_Tabs::reset($data->name);
|
||||
|
||||
$this->refresh();
|
||||
}
|
||||
@ -399,6 +405,7 @@ class Connection_Sidebar extends GtkVBox {
|
||||
* Change tabs based on db connection selected
|
||||
*
|
||||
* @param type $view
|
||||
* @return void
|
||||
*/
|
||||
public function switch_tab($view)
|
||||
{
|
||||
|
@ -67,7 +67,9 @@ class Data_Grid extends GtkTreeView {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Empty the model
|
||||
* Clear datagrid
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
@ -112,9 +114,10 @@ class Data_Grid extends GtkTreeView {
|
||||
* Create a datagrid from the provided data array
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $events
|
||||
* @return void
|
||||
*/
|
||||
public function render_data($data)
|
||||
public function render_data($data, $events=array())
|
||||
{
|
||||
if ( ! is_array($data))
|
||||
{
|
||||
|
@ -102,7 +102,7 @@ class DB_Info_Widget extends GtkTable {
|
||||
$this->port->set_text($db->port);
|
||||
|
||||
// Layout the table
|
||||
$this->layout();
|
||||
$this->_layout();
|
||||
|
||||
// Select the proper db type if editing
|
||||
if ( ! empty($db->type))
|
||||
@ -136,104 +136,6 @@ class DB_Info_Widget extends GtkTable {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Table layout
|
||||
*/
|
||||
public function layout()
|
||||
{
|
||||
// Reset defaults when changing db types
|
||||
$this->dbtype->connect_simple("changed", array($this, "change_db"));
|
||||
|
||||
//Table attach
|
||||
//$tbl->attach(left_start, right_stop, top_start, bottom_stop)
|
||||
|
||||
// Placeholder vars for y values, so that rows can be
|
||||
// easily moved
|
||||
$y1 = -1;
|
||||
$y2 = 0;
|
||||
|
||||
// Connection name
|
||||
{
|
||||
$this->_add_row("Connection name", 'conn', $y1, $y2);
|
||||
}
|
||||
|
||||
// Database type
|
||||
{
|
||||
$dbtypelbl = new GtkLabel("Database Type");
|
||||
$typealign = new GtkAlignment(0, 0.5, 0, 0);
|
||||
$typealign->add($dbtypelbl);
|
||||
$this->attach($typealign, 0, 1, ++$y1, ++$y2);
|
||||
$this->attach($this->dbtype, 1, 2, $y1, $y2);
|
||||
}
|
||||
|
||||
// DB File
|
||||
{
|
||||
$this->_add_row("Database File", 'db_file', $y1, $y2);
|
||||
}
|
||||
|
||||
// First Db
|
||||
{
|
||||
$this->_add_row("Database Name", 'conn_db', $y1, $y2);
|
||||
}
|
||||
|
||||
// Host
|
||||
{
|
||||
$this->_add_row("Host", 'host', $y1, $y2);
|
||||
}
|
||||
|
||||
// Port
|
||||
{
|
||||
$this->_add_row("Port", 'port', $y1, $y2);
|
||||
}
|
||||
|
||||
// Username
|
||||
{
|
||||
$this->_add_row("User", 'user', $y1, $y2);
|
||||
}
|
||||
|
||||
// Password
|
||||
{
|
||||
$this->_add_row("Password", 'pass', $y1, $y2);
|
||||
}
|
||||
|
||||
// Add/Edit connection button
|
||||
{
|
||||
$conn_name = $this->conn->get_text();
|
||||
$caption = (empty($conn_name)) ? 'Add Connection' : 'Update Connection';
|
||||
|
||||
$add_button = new GtkButton();
|
||||
$add_button->set_label($caption);
|
||||
|
||||
( ! empty($conn_name))
|
||||
? $add_button->set_image(GTKImage::new_from_stock(GTK::STOCK_SAVE,
|
||||
GTK::ICON_SIZE_SMALL_TOOLBAR))
|
||||
: $add_button->set_image(GTKImage::new_from_stock(GTK::STOCK_ADD,
|
||||
Gtk::ICON_SIZE_SMALL_TOOLBAR));
|
||||
|
||||
$this->attach($add_button, 0, 1, ++$y1, ++$y2);
|
||||
|
||||
if ( ! empty($conn_name))
|
||||
{
|
||||
$add_button->connect_simple("clicked", array($this, 'db_edit'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$add_button->connect_simple("clicked", array($this, 'db_add'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test connection button
|
||||
{
|
||||
$test_button = new GtkButton();
|
||||
$test_button->set_label("Test Connection");
|
||||
$this->attach($test_button, 1, 2, $y1, $y2);
|
||||
$test_button->connect_simple("clicked", array($this, 'test_conn'));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set defaults for new database type
|
||||
*
|
||||
@ -350,6 +252,8 @@ class DB_Info_Widget extends GtkTable {
|
||||
|
||||
/**
|
||||
* Adds the database to the settings file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function db_add()
|
||||
{
|
||||
@ -383,6 +287,8 @@ class DB_Info_Widget extends GtkTable {
|
||||
|
||||
/**
|
||||
* Edit an existing database connection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function db_edit()
|
||||
{
|
||||
@ -419,6 +325,8 @@ class DB_Info_Widget extends GtkTable {
|
||||
|
||||
/**
|
||||
* Test a db connection, and display a popup with the result of the test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_conn()
|
||||
{
|
||||
@ -524,6 +432,7 @@ class DB_Info_Widget extends GtkTable {
|
||||
* @param string $vname
|
||||
* @param int &$y1
|
||||
* @param int &$y2
|
||||
* @return void
|
||||
*/
|
||||
private function _add_row($label, $vname, &$y1, &$y2)
|
||||
{
|
||||
@ -538,5 +447,105 @@ class DB_Info_Widget extends GtkTable {
|
||||
$this->attach($lblalign, 0, 1, ++$y1, ++$y2);
|
||||
$this->attach($vname, 1, 2, $y1, $y2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Table layout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _layout()
|
||||
{
|
||||
// Reset defaults when changing db types
|
||||
$this->dbtype->connect_simple("changed", array($this, "change_db"));
|
||||
|
||||
//Table attach
|
||||
//$tbl->attach(left_start, right_stop, top_start, bottom_stop)
|
||||
|
||||
// Placeholder vars for y values, so that rows can be
|
||||
// easily moved
|
||||
$y1 = -1;
|
||||
$y2 = 0;
|
||||
|
||||
// Connection name
|
||||
{
|
||||
$this->_add_row("Connection name", 'conn', $y1, $y2);
|
||||
}
|
||||
|
||||
// Database type
|
||||
{
|
||||
$dbtypelbl = new GtkLabel("Database Type");
|
||||
$typealign = new GtkAlignment(0, 0.5, 0, 0);
|
||||
$typealign->add($dbtypelbl);
|
||||
$this->attach($typealign, 0, 1, ++$y1, ++$y2);
|
||||
$this->attach($this->dbtype, 1, 2, $y1, $y2);
|
||||
}
|
||||
|
||||
// DB File
|
||||
{
|
||||
$this->_add_row("Database File", 'db_file', $y1, $y2);
|
||||
}
|
||||
|
||||
// First Db
|
||||
{
|
||||
$this->_add_row("Database Name", 'conn_db', $y1, $y2);
|
||||
}
|
||||
|
||||
// Host
|
||||
{
|
||||
$this->_add_row("Host", 'host', $y1, $y2);
|
||||
}
|
||||
|
||||
// Port
|
||||
{
|
||||
$this->_add_row("Port", 'port', $y1, $y2);
|
||||
}
|
||||
|
||||
// Username
|
||||
{
|
||||
$this->_add_row("User", 'user', $y1, $y2);
|
||||
}
|
||||
|
||||
// Password
|
||||
{
|
||||
$this->_add_row("Password", 'pass', $y1, $y2);
|
||||
}
|
||||
|
||||
// Add/Edit connection button
|
||||
{
|
||||
$conn_name = $this->conn->get_text();
|
||||
$caption = (empty($conn_name)) ? 'Add Connection' : 'Update Connection';
|
||||
|
||||
$add_button = new GtkButton();
|
||||
$add_button->set_label($caption);
|
||||
|
||||
( ! empty($conn_name))
|
||||
? $add_button->set_image(GTKImage::new_from_stock(GTK::STOCK_SAVE,
|
||||
GTK::ICON_SIZE_SMALL_TOOLBAR))
|
||||
: $add_button->set_image(GTKImage::new_from_stock(GTK::STOCK_ADD,
|
||||
Gtk::ICON_SIZE_SMALL_TOOLBAR));
|
||||
|
||||
$this->attach($add_button, 0, 1, ++$y1, ++$y2);
|
||||
|
||||
if ( ! empty($conn_name))
|
||||
{
|
||||
$add_button->connect_simple("clicked", array($this, 'db_edit'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$add_button->connect_simple("clicked", array($this, 'db_add'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test connection button
|
||||
{
|
||||
$test_button = new GtkButton();
|
||||
$test_button->set_label("Test Connection");
|
||||
$this->attach($test_button, 1, 2, $y1, $y2);
|
||||
$test_button->connect_simple("clicked", array($this, 'test_conn'));
|
||||
}
|
||||
}
|
||||
}
|
||||
// End of db_info_widget.php
|
@ -71,6 +71,27 @@ class DB_tabs extends GTKNotebook {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create popup window with table data
|
||||
*
|
||||
* @param GTKTreeView $view
|
||||
* @param array $path
|
||||
* @param GtkTreeviewColumn $col
|
||||
* @param Query_Builder $conn
|
||||
* @return void
|
||||
*/
|
||||
public function show_table_data($view, $path, $col, &$conn)
|
||||
{
|
||||
$table = $view->get(0);
|
||||
|
||||
$query = $conn->get($table);
|
||||
$data = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
return new DB_Table_data($data);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create tabs for database aspects
|
||||
*
|
||||
@ -85,9 +106,9 @@ class DB_tabs extends GTKNotebook {
|
||||
self::$instance->hide_all();
|
||||
|
||||
// 'Databases' Tab
|
||||
{
|
||||
/*{
|
||||
self::_add_tab($conn, 'Databases', 'Db Name', 'get_dbs');
|
||||
}
|
||||
}*/
|
||||
|
||||
// 'Schemas' Tab
|
||||
{
|
||||
@ -106,9 +127,15 @@ class DB_tabs extends GTKNotebook {
|
||||
}
|
||||
|
||||
// 'System Tables' Tab
|
||||
{
|
||||
self::_add_tab($conn, 'System Tables', 'Table Name', 'get_system_tables');
|
||||
}
|
||||
/*{
|
||||
self::_add_tab($conn, 'System Tables', 'Table Name', 'get_system_tables', array(
|
||||
array(
|
||||
'row-activated',
|
||||
array(self::$instance, 'show_table_data'),
|
||||
$conn
|
||||
)
|
||||
));
|
||||
}*/
|
||||
|
||||
// 'Views' Tab
|
||||
{
|
||||
@ -150,8 +177,11 @@ class DB_tabs extends GTKNotebook {
|
||||
|
||||
/**
|
||||
* Remove current tabs
|
||||
*
|
||||
* @param string $conn_name
|
||||
* @return void
|
||||
*/
|
||||
public static function reset()
|
||||
public static function reset($conn_name = '')
|
||||
{
|
||||
self::$instance->hide_all();
|
||||
|
||||
@ -160,6 +190,11 @@ class DB_tabs extends GTKNotebook {
|
||||
self::$instance->remove_page($i);
|
||||
}
|
||||
|
||||
if ( ! empty($conn_name))
|
||||
{
|
||||
unset(self::$instance->data->{$conn_name});
|
||||
}
|
||||
|
||||
self::$instance->show_all();
|
||||
}
|
||||
|
||||
@ -182,18 +217,13 @@ class DB_tabs extends GTKNotebook {
|
||||
|
||||
$conn_name = $conn->conn_name;
|
||||
|
||||
if ( ! isset(self::$instance->data->{$conn_name}))
|
||||
{
|
||||
self::$instance->data->{$conn_name}= array();
|
||||
}
|
||||
$instance_data = self::$instance->_get_db_info($conn_name, $tab_name);
|
||||
|
||||
$instance_data =& self::$instance->data->{$conn_name};
|
||||
|
||||
$tab_data = (empty($instance_data[$tab_name]))
|
||||
$tab_data = ($instance_data === FALSE)
|
||||
? call_user_func_array(array($conn, $method), array())
|
||||
: $instance_data[$tab_name];
|
||||
: $instance_data;
|
||||
|
||||
$instance_data[$tab_name] = $tab_data;
|
||||
self::$instance->_set_db_info($conn_name, $tab_name, $tab_data);
|
||||
|
||||
if ($tab_data !== FALSE)
|
||||
{
|
||||
@ -236,18 +266,13 @@ class DB_tabs extends GTKNotebook {
|
||||
|
||||
$conn_name = $conn->conn_name;
|
||||
|
||||
if ( ! isset(self::$instance->data->{$conn_name}))
|
||||
{
|
||||
self::$instance->data->{$conn_name}= array();
|
||||
}
|
||||
$instance_data = self::$instance->_get_db_info($conn_name, $tab_name);
|
||||
|
||||
$instance_data =& self::$instance->data->{$conn_name};
|
||||
|
||||
$tab_data = (empty($instance_data[$tab_name]))
|
||||
$tab_data = ($instance_data === FALSE)
|
||||
? call_user_func_array(array($conn, $method), array())
|
||||
: $instance_data[$tab_name];
|
||||
: $instance_data;
|
||||
|
||||
$instance_data[$tab_name] = $tab_data;
|
||||
self::$instance->_set_db_info($conn_name, $tab_name, $tab_data);
|
||||
|
||||
if ( ! empty($tab_data))
|
||||
{
|
||||
@ -263,22 +288,42 @@ class DB_tabs extends GTKNotebook {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create popup window with table data
|
||||
* Returns cached database data for the tab and connection specified
|
||||
*
|
||||
* @param GTKTreeView $view
|
||||
* @param array $path
|
||||
* @param GtkTreeviewColumn $col
|
||||
* @param Query_Builder $conn
|
||||
* @return void
|
||||
* @param type $conn_name
|
||||
* @param type $tab_name
|
||||
* @return mixed
|
||||
*/
|
||||
public function show_table_data($view, $path, $col, &$conn)
|
||||
private function _get_db_info($conn_name, $tab_name)
|
||||
{
|
||||
$table = $view->get(0);
|
||||
$data =& self::$instance->data;
|
||||
|
||||
$query = $conn->get($table);
|
||||
$data = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
if ( ! isset($data->{$conn_name}))
|
||||
{
|
||||
$data->{$conn_name}= array();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return new DB_Table_data($data);
|
||||
if ( ! isset($data->{$conn_name}[$tab_name]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $data->{$conn_name}[$tab_name];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets cached database data for the tab and connection specified
|
||||
*
|
||||
* @param type $conn_name
|
||||
* @param type $tab_name
|
||||
* @param type $data
|
||||
*/
|
||||
private function _set_db_info($conn_name, $tab_name, $data)
|
||||
{
|
||||
self::$instance->data->{$conn_name}[$tab_name] = $data;
|
||||
}
|
||||
}
|
||||
// End of db_tabs.php
|
||||
|
@ -23,37 +23,26 @@ class DB_Table_Data extends GTKWindow {
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
||||
$this->set_title("Table Data");
|
||||
$this->set_position(Gtk::WIN_POS_CENTER_ALWAYS);
|
||||
$this->set_destroy_with_parent(TRUE);
|
||||
|
||||
// Add the scrolled window
|
||||
$this->win = new GTKScrolledWindow();
|
||||
$this->win->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
|
||||
$this->add($this->win);
|
||||
|
||||
$this->_render($data);
|
||||
|
||||
// Resize to a sane size
|
||||
|
||||
$this->set_size_request(640, 480);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout the window
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function _render($data)
|
||||
{
|
||||
// Layout the widgets
|
||||
$view = new Data_Grid();
|
||||
$view->render_data($data);
|
||||
|
||||
// Add the grid to the window
|
||||
$this->win->add_with_viewport($view);
|
||||
|
||||
// Show everything
|
||||
$this->show_all();
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ class Main extends GtkWindow {
|
||||
|
||||
/**
|
||||
* Some cleanup for when the main window is closed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
@ -78,7 +80,9 @@ class Main extends GtkWindow {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Quits the GTK loop
|
||||
* Exits the GTK loop
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function quit()
|
||||
{
|
||||
|
Reference in New Issue
Block a user