Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpmyadmin/phpmyadmin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaurício Meneghini Fauth <mauricio@fauth.dev>2021-09-08 03:19:43 +0300
committerMaurício Meneghini Fauth <mauricio@fauth.dev>2021-09-08 03:19:43 +0300
commite3554879ef7a4879446db25669563df004f832a2 (patch)
tree6a5788e42622d01918d81971e93b178dd09a6831
parenta73e26c81f0ed01fe717e476ab3c7937efa702e4 (diff)
Extract actions from controllers to new controllers
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
-rw-r--r--libraries/classes/Controllers/Database/Operations/CollationController.php112
-rw-r--r--libraries/classes/Controllers/Database/OperationsController.php72
-rw-r--r--libraries/classes/Controllers/Database/Structure/AddPrefixController.php34
-rw-r--r--libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php64
-rw-r--r--libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php59
-rw-r--r--libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php59
-rw-r--r--libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php59
-rw-r--r--libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php43
-rw-r--r--libraries/classes/Controllers/Database/Structure/CopyFormController.php45
-rw-r--r--libraries/classes/Controllers/Database/Structure/CopyTableController.php81
-rw-r--r--libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php67
-rw-r--r--libraries/classes/Controllers/Database/Structure/DropFormController.php86
-rw-r--r--libraries/classes/Controllers/Database/Structure/DropTableController.php136
-rw-r--r--libraries/classes/Controllers/Database/Structure/EmptyFormController.php44
-rw-r--r--libraries/classes/Controllers/Database/Structure/EmptyTableController.php123
-rw-r--r--libraries/classes/Controllers/Database/Structure/FavoriteTableController.php193
-rw-r--r--libraries/classes/Controllers/Database/Structure/RealRowCountController.php84
-rw-r--r--libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php76
-rw-r--r--libraries/classes/Controllers/Database/Structure/ShowCreateController.php69
-rw-r--r--libraries/classes/Controllers/Database/StructureController.php763
-rw-r--r--libraries/classes/Controllers/Export/CheckTimeOutController.php24
-rw-r--r--libraries/classes/Controllers/Export/ExportController.php14
-rw-r--r--libraries/classes/Controllers/Server/Databases/CreateController.php119
-rw-r--r--libraries/classes/Controllers/Server/Databases/DestroyController.php122
-rw-r--r--libraries/classes/Controllers/Server/DatabasesController.php166
-rw-r--r--libraries/routes.php62
-rw-r--r--libraries/services_controllers.php197
-rw-r--r--psalm-baseline.xml599
-rw-r--r--test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php63
-rw-r--r--test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php50
-rw-r--r--test/classes/Controllers/Database/StructureControllerTest.php111
-rw-r--r--test/classes/Controllers/Server/Databases/CreateControllerTest.php61
-rw-r--r--test/classes/Controllers/Server/Databases/DestroyControllerTest.php58
-rw-r--r--test/classes/Controllers/Server/DatabasesControllerTest.php86
-rw-r--r--test/classes/Stubs/DbiDummy.php113
35 files changed, 2667 insertions, 1447 deletions
diff --git a/libraries/classes/Controllers/Database/Operations/CollationController.php b/libraries/classes/Controllers/Database/Operations/CollationController.php
new file mode 100644
index 0000000000..212e893324
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Operations/CollationController.php
@@ -0,0 +1,112 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Operations;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\Operations;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Url;
+use PhpMyAdmin\Util;
+
+use function __;
+
+final class CollationController extends AbstractController
+{
+ /** @var Operations */
+ private $operations;
+
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db Database name
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct(
+ $response,
+ Template $template,
+ $db,
+ Operations $operations,
+ $dbi
+ ) {
+ parent::__construct($response, $template, $db);
+ $this->operations = $operations;
+ $this->dbi = $dbi;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $cfg, $errorUrl;
+
+ if (! $this->response->isAjax()) {
+ return;
+ }
+
+ if (empty($_POST['db_collation'])) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', Message::error(__('No collation provided.')));
+
+ return;
+ }
+
+ Util::checkParameters(['db']);
+
+ $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
+ $errorUrl .= Url::getCommon(['db' => $db], '&');
+
+ if (! $this->hasDatabase()) {
+ return;
+ }
+
+ $sql_query = 'ALTER DATABASE ' . Util::backquote($db)
+ . ' DEFAULT' . Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
+ $this->dbi->query($sql_query);
+ $message = Message::success();
+
+ /**
+ * Changes tables charset if requested by the user
+ */
+ if (
+ isset($_POST['change_all_tables_collations']) &&
+ $_POST['change_all_tables_collations'] === 'on'
+ ) {
+ [$tables] = Util::getDbInfo($db, null);
+ foreach ($tables as $tableName => $data) {
+ if ($this->dbi->getTable($db, $tableName)->isView()) {
+ // Skip views, we can not change the collation of a view.
+ // issue #15283
+ continue;
+ }
+
+ $sql_query = 'ALTER TABLE '
+ . Util::backquote($db)
+ . '.'
+ . Util::backquote($tableName)
+ . ' DEFAULT '
+ . Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
+ $this->dbi->query($sql_query);
+
+ /**
+ * Changes columns charset if requested by the user
+ */
+ if (
+ ! isset($_POST['change_all_tables_columns_collations']) ||
+ $_POST['change_all_tables_columns_collations'] !== 'on'
+ ) {
+ continue;
+ }
+
+ $this->operations->changeAllColumnsCollation($db, $tableName, $_POST['db_collation']);
+ }
+ }
+
+ $this->response->setRequestStatus($message->isSuccess());
+ $this->response->addJSON('message', $message);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/OperationsController.php b/libraries/classes/Controllers/Database/OperationsController.php
index 3d9566a860..17f148293c 100644
--- a/libraries/classes/Controllers/Database/OperationsController.php
+++ b/libraries/classes/Controllers/Database/OperationsController.php
@@ -68,7 +68,7 @@ class OperationsController extends AbstractController
$this->dbi = $dbi;
}
- public function index(): void
+ public function __invoke(): void
{
global $cfg, $db, $server, $sql_query, $move, $message, $tables_full, $errorUrl;
global $export_sql_plugin, $views, $sqlConstratints, $local_query, $reload, $urlParams, $tables;
@@ -354,74 +354,4 @@ class OperationsController extends AbstractController
'collations' => $collations,
]);
}
-
- public function collation(): void
- {
- global $db, $cfg, $errorUrl;
-
- if (! $this->response->isAjax()) {
- return;
- }
-
- if (empty($_POST['db_collation'])) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', Message::error(__('No collation provided.')));
-
- return;
- }
-
- Util::checkParameters(['db']);
-
- $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
- $errorUrl .= Url::getCommon(['db' => $db], '&');
-
- if (! $this->hasDatabase()) {
- return;
- }
-
- $sql_query = 'ALTER DATABASE ' . Util::backquote($db)
- . ' DEFAULT' . Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
- $this->dbi->query($sql_query);
- $message = Message::success();
-
- /**
- * Changes tables charset if requested by the user
- */
- if (
- isset($_POST['change_all_tables_collations']) &&
- $_POST['change_all_tables_collations'] === 'on'
- ) {
- [$tables] = Util::getDbInfo($db, null);
- foreach ($tables as $tableName => $data) {
- if ($this->dbi->getTable($db, $tableName)->isView()) {
- // Skip views, we can not change the collation of a view.
- // issue #15283
- continue;
- }
-
- $sql_query = 'ALTER TABLE '
- . Util::backquote($db)
- . '.'
- . Util::backquote($tableName)
- . ' DEFAULT '
- . Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
- $this->dbi->query($sql_query);
-
- /**
- * Changes columns charset if requested by the user
- */
- if (
- ! isset($_POST['change_all_tables_columns_collations']) ||
- $_POST['change_all_tables_columns_collations'] !== 'on'
- ) {
- continue;
- }
-
- $this->operations->changeAllColumnsCollation($db, $tableName, $_POST['db_collation']);
- }
- }
-
- $this->response->setRequestStatus($message->isSuccess());
- $this->response->addJSON('message', $message);
- }
}
diff --git a/libraries/classes/Controllers/Database/Structure/AddPrefixController.php b/libraries/classes/Controllers/Database/Structure/AddPrefixController.php
new file mode 100644
index 0000000000..7a7cfadc29
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/AddPrefixController.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+
+use function __;
+
+final class AddPrefixController extends AbstractController
+{
+ public function __invoke(): void
+ {
+ global $db;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $params = ['db' => $db];
+ foreach ($selected as $selectedValue) {
+ $params['selected'][] = $selectedValue;
+ }
+
+ $this->response->disable();
+ $this->render('database/structure/add_prefix', ['url_params' => $params]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php b/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php
new file mode 100644
index 0000000000..711a562d6d
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Util;
+
+use function count;
+
+final class AddPrefixTableController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message, $sql_query;
+
+ $selected = $_POST['selected'] ?? [];
+
+ $sql_query = '';
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ $newTableName = $_POST['add_prefix'] . $selected[$i];
+ $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
+ . ' RENAME ' . Util::backquote($newTableName);
+
+ $sql_query .= $aQuery . ';' . "\n";
+ $this->dbi->selectDb($db);
+ $this->dbi->query($aQuery);
+ }
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php
new file mode 100644
index 0000000000..cb10f368c6
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\Database\CentralColumns;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+
+use function __;
+
+final class AddController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $message;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $centralColumns = new CentralColumns($this->dbi);
+ $error = $centralColumns->syncUniqueColumns($selected);
+
+ $message = $error instanceof Message ? $error : Message::success(__('Success!'));
+
+ unset($_POST['submit_mult']);
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php
new file mode 100644
index 0000000000..a0dfe49e70
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\Database\CentralColumns;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+
+use function __;
+
+final class MakeConsistentController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $centralColumns = new CentralColumns($this->dbi);
+ $error = $centralColumns->makeConsistentWithList($db, $selected);
+
+ $message = $error instanceof Message ? $error : Message::success(__('Success!'));
+
+ unset($_POST['submit_mult']);
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php b/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php
new file mode 100644
index 0000000000..c58785214c
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\Database\CentralColumns;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+
+use function __;
+
+final class RemoveController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $message;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $centralColumns = new CentralColumns($this->dbi);
+ $error = $centralColumns->deleteColumnsFromList($_POST['db'], $selected);
+
+ $message = $error instanceof Message ? $error : Message::success(__('Success!'));
+
+ unset($_POST['submit_mult']);
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php b/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php
new file mode 100644
index 0000000000..6529585125
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+
+use function __;
+
+final class ChangePrefixFormController extends AbstractController
+{
+ public function __invoke(): void
+ {
+ global $db;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+ $submitMult = $_POST['submit_mult'] ?? '';
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $route = '/database/structure/replace-prefix';
+ if ($submitMult === 'copy_tbl_change_prefix') {
+ $route = '/database/structure/copy-table-with-prefix';
+ }
+
+ $urlParams = ['db' => $db];
+ foreach ($selected as $selectedValue) {
+ $urlParams['selected'][] = $selectedValue;
+ }
+
+ $this->response->disable();
+ $this->render('database/structure/change_prefix_form', [
+ 'route' => $route,
+ 'url_params' => $urlParams,
+ ]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CopyFormController.php b/libraries/classes/Controllers/Database/Structure/CopyFormController.php
new file mode 100644
index 0000000000..70ba831009
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CopyFormController.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+
+use function __;
+
+final class CopyFormController extends AbstractController
+{
+ public function __invoke(): void
+ {
+ global $db, $dblist;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $urlParams = ['db' => $db];
+ foreach ($selected as $selectedValue) {
+ $urlParams['selected'][] = $selectedValue;
+ }
+
+ $databasesList = $dblist->databases;
+ foreach ($databasesList as $key => $databaseName) {
+ if ($databaseName == $db) {
+ $databasesList->offsetUnset($key);
+ break;
+ }
+ }
+
+ $this->response->disable();
+ $this->render('database/structure/copy_form', [
+ 'url_params' => $urlParams,
+ 'options' => $databasesList->getList(),
+ ]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CopyTableController.php b/libraries/classes/Controllers/Database/Structure/CopyTableController.php
new file mode 100644
index 0000000000..7af069693c
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CopyTableController.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\Operations;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Table;
+use PhpMyAdmin\Template;
+
+use function count;
+
+final class CopyTableController extends AbstractController
+{
+ /** @var Operations */
+ private $operations;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ */
+ public function __construct(
+ $response,
+ Template $template,
+ $db,
+ Operations $operations,
+ StructureController $structureController
+ ) {
+ parent::__construct($response, $template, $db);
+ $this->operations = $operations;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message;
+
+ $selected = $_POST['selected'] ?? [];
+ $targetDb = $_POST['target_db'] ?? null;
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ Table::moveCopy(
+ $db,
+ $selected[$i],
+ $targetDb,
+ $selected[$i],
+ $_POST['what'],
+ false,
+ 'one_table',
+ isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
+ );
+
+ if (empty($_POST['adjust_privileges'])) {
+ continue;
+ }
+
+ $this->operations->adjustPrivilegesCopyTable(
+ $db,
+ $selected[$i],
+ $targetDb,
+ $selected[$i]
+ );
+ }
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php b/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php
new file mode 100644
index 0000000000..de07cf8f4b
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Table;
+use PhpMyAdmin\Template;
+
+use function count;
+use function mb_strlen;
+use function mb_substr;
+
+final class CopyTableWithPrefixController extends AbstractController
+{
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ */
+ public function __construct($response, Template $template, $db, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message;
+
+ $selected = $_POST['selected'] ?? [];
+ $fromPrefix = $_POST['from_prefix'] ?? null;
+ $toPrefix = $_POST['to_prefix'] ?? null;
+
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ $current = $selected[$i];
+ $newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix));
+
+ Table::moveCopy(
+ $db,
+ $current,
+ $db,
+ $newTableName,
+ 'data',
+ false,
+ 'one_table',
+ isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
+ );
+ }
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/DropFormController.php b/libraries/classes/Controllers/Database/Structure/DropFormController.php
new file mode 100644
index 0000000000..91793c1373
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/DropFormController.php
@@ -0,0 +1,86 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Util;
+use PhpMyAdmin\Utils\ForeignKey;
+
+use function __;
+use function htmlspecialchars;
+use function in_array;
+
+final class DropFormController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ }
+
+ public function __invoke(): void
+ {
+ global $db;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $views = $this->dbi->getVirtualTables($db);
+
+ $fullQueryViews = '';
+ $fullQuery = '';
+
+ foreach ($selected as $selectedValue) {
+ $current = $selectedValue;
+ if (! empty($views) && in_array($current, $views)) {
+ $fullQueryViews .= (empty($fullQueryViews) ? 'DROP VIEW ' : ', ')
+ . Util::backquote(htmlspecialchars($current));
+ } else {
+ $fullQuery .= (empty($fullQuery) ? 'DROP TABLE ' : ', ')
+ . Util::backquote(htmlspecialchars($current));
+ }
+ }
+
+ if (! empty($fullQuery)) {
+ $fullQuery .= ';<br>' . "\n";
+ }
+
+ if (! empty($fullQueryViews)) {
+ $fullQuery .= $fullQueryViews . ';<br>' . "\n";
+ }
+
+ $urlParams = ['db' => $db];
+ foreach ($selected as $selectedValue) {
+ $urlParams['selected'][] = $selectedValue;
+ }
+
+ foreach ($views as $current) {
+ $urlParams['views'][] = $current;
+ }
+
+ $this->render('database/structure/drop_form', [
+ 'url_params' => $urlParams,
+ 'full_query' => $fullQuery,
+ 'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
+ ]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/DropTableController.php b/libraries/classes/Controllers/Database/Structure/DropTableController.php
new file mode 100644
index 0000000000..113a918eed
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/DropTableController.php
@@ -0,0 +1,136 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\RelationCleanup;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Util;
+use PhpMyAdmin\Utils\ForeignKey;
+
+use function __;
+use function count;
+use function in_array;
+
+final class DropTableController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var RelationCleanup */
+ private $relationCleanup;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct(
+ $response,
+ Template $template,
+ $db,
+ $dbi,
+ RelationCleanup $relationCleanup,
+ StructureController $structureController
+ ) {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->relationCleanup = $relationCleanup;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message, $reload, $sql_query;
+
+ $reload = $_POST['reload'] ?? $reload ?? null;
+ $multBtn = $_POST['mult_btn'] ?? '';
+ $selected = $_POST['selected'] ?? [];
+
+ $views = $this->dbi->getVirtualTables($db);
+
+ if ($multBtn !== __('Yes')) {
+ $message = Message::success(__('No change'));
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = Message::success();
+ }
+
+ unset($_POST['mult_btn']);
+
+ ($this->structureController)();
+
+ return;
+ }
+
+ $defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
+ $sql_query = '';
+ $sqlQueryViews = '';
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ $this->relationCleanup->table($db, $selected[$i]);
+ $current = $selected[$i];
+
+ if (! empty($views) && in_array($current, $views)) {
+ $sqlQueryViews .= (empty($sqlQueryViews) ? 'DROP VIEW ' : ', ') . Util::backquote($current);
+ } else {
+ $sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') . Util::backquote($current);
+ }
+
+ $reload = 1;
+ }
+
+ if (! empty($sql_query)) {
+ $sql_query .= ';';
+ } elseif (! empty($sqlQueryViews)) {
+ $sql_query = $sqlQueryViews . ';';
+ unset($sqlQueryViews);
+ }
+
+ // Unset cache values for tables count, issue #14205
+ if (isset($_SESSION['tmpval'])) {
+ if (isset($_SESSION['tmpval']['table_limit_offset'])) {
+ unset($_SESSION['tmpval']['table_limit_offset']);
+ }
+
+ if (isset($_SESSION['tmpval']['table_limit_offset_db'])) {
+ unset($_SESSION['tmpval']['table_limit_offset_db']);
+ }
+ }
+
+ $this->dbi->selectDb($db);
+ $result = $this->dbi->tryQuery($sql_query);
+
+ if ($result && ! empty($sqlQueryViews)) {
+ $sql_query .= ' ' . $sqlQueryViews . ';';
+ $result = $this->dbi->tryQuery($sqlQueryViews);
+ unset($sqlQueryViews);
+ }
+
+ if (! $result) {
+ $message = Message::error((string) $this->dbi->getError());
+ }
+
+ ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ unset($_POST['mult_btn']);
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/EmptyFormController.php b/libraries/classes/Controllers/Database/Structure/EmptyFormController.php
new file mode 100644
index 0000000000..556d64493b
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/EmptyFormController.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Util;
+use PhpMyAdmin\Utils\ForeignKey;
+
+use function __;
+use function htmlspecialchars;
+
+final class EmptyFormController extends AbstractController
+{
+ public function __invoke(): void
+ {
+ global $db;
+
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $fullQuery = '';
+ $urlParams = ['db' => $db];
+
+ foreach ($selected as $selectedValue) {
+ $fullQuery .= 'TRUNCATE ';
+ $fullQuery .= Util::backquote(htmlspecialchars($selectedValue)) . ';<br>';
+ $urlParams['selected'][] = $selectedValue;
+ }
+
+ $this->render('database/structure/empty_form', [
+ 'url_params' => $urlParams,
+ 'full_query' => $fullQuery,
+ 'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
+ ]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/EmptyTableController.php b/libraries/classes/Controllers/Database/Structure/EmptyTableController.php
new file mode 100644
index 0000000000..c543eb0090
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/EmptyTableController.php
@@ -0,0 +1,123 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\FlashMessages;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\Operations;
+use PhpMyAdmin\Relation;
+use PhpMyAdmin\RelationCleanup;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Sql;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Util;
+use PhpMyAdmin\Utils\ForeignKey;
+
+use function __;
+use function count;
+
+final class EmptyTableController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var Relation */
+ private $relation;
+
+ /** @var RelationCleanup */
+ private $relationCleanup;
+
+ /** @var Operations */
+ private $operations;
+
+ /** @var FlashMessages */
+ private $flash;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct(
+ $response,
+ Template $template,
+ $db,
+ $dbi,
+ Relation $relation,
+ RelationCleanup $relationCleanup,
+ Operations $operations,
+ FlashMessages $flash,
+ StructureController $structureController
+ ) {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->relation = $relation;
+ $this->relationCleanup = $relationCleanup;
+ $this->operations = $operations;
+ $this->flash = $flash;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $table, $message, $sql_query;
+
+ $multBtn = $_POST['mult_btn'] ?? '';
+ $selected = $_POST['selected'] ?? [];
+
+ if ($multBtn !== __('Yes')) {
+ $this->flash->addMessage('success', __('No change'));
+ $this->redirect('/database/structure', ['db' => $db]);
+
+ return;
+ }
+
+ $defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
+
+ $sql_query = '';
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ $aQuery = 'TRUNCATE ';
+ $aQuery .= Util::backquote($selected[$i]);
+
+ $sql_query .= $aQuery . ';' . "\n";
+ $this->dbi->selectDb($db);
+ $this->dbi->query($aQuery);
+ }
+
+ if (! empty($_REQUEST['pos'])) {
+ $sql = new Sql(
+ $this->dbi,
+ $this->relation,
+ $this->relationCleanup,
+ $this->operations,
+ new Transformations(),
+ $this->template
+ );
+
+ $_REQUEST['pos'] = $sql->calculatePosForLastPage($db, $table, $_REQUEST['pos']);
+ }
+
+ ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ unset($_POST['mult_btn']);
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
new file mode 100644
index 0000000000..596dc6de9d
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/FavoriteTableController.php
@@ -0,0 +1,193 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\RecentFavoriteTable;
+use PhpMyAdmin\Relation;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Url;
+use PhpMyAdmin\Util;
+
+use function __;
+use function count;
+use function json_decode;
+use function json_encode;
+use function md5;
+use function sha1;
+
+final class FavoriteTableController extends AbstractController
+{
+ /** @var Relation */
+ private $relation;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ */
+ public function __construct($response, Template $template, $db, Relation $relation)
+ {
+ parent::__construct($response, $template, $db);
+ $this->relation = $relation;
+ }
+
+ public function __invoke(): void
+ {
+ global $cfg, $db, $errorUrl;
+
+ $parameters = [
+ 'favorite_table' => $_REQUEST['favorite_table'] ?? null,
+ 'favoriteTables' => $_REQUEST['favoriteTables'] ?? null,
+ 'sync_favorite_tables' => $_REQUEST['sync_favorite_tables'] ?? null,
+ ];
+
+ Util::checkParameters(['db']);
+
+ $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
+ $errorUrl .= Url::getCommon(['db' => $db], '&');
+
+ if (! $this->hasDatabase() || ! $this->response->isAjax()) {
+ return;
+ }
+
+ $favoriteInstance = RecentFavoriteTable::getInstance('favorite');
+ if (isset($parameters['favoriteTables'])) {
+ $favoriteTables = json_decode($parameters['favoriteTables'], true);
+ } else {
+ $favoriteTables = [];
+ }
+
+ // Required to keep each user's preferences separate.
+ $user = sha1($cfg['Server']['user']);
+
+ // Request for Synchronization of favorite tables.
+ if (isset($parameters['sync_favorite_tables'])) {
+ $cfgRelation = $this->relation->getRelationsParam();
+ if ($cfgRelation['favoritework']) {
+ $this->response->addJSON($this->synchronizeFavoriteTables(
+ $favoriteInstance,
+ $user,
+ $favoriteTables
+ ));
+ }
+
+ return;
+ }
+
+ $changes = true;
+ $favoriteTable = $parameters['favorite_table'] ?? '';
+ $alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
+
+ if (isset($_REQUEST['remove_favorite'])) {
+ if ($alreadyFavorite) {
+ // If already in favorite list, remove it.
+ $favoriteInstance->remove($this->db, $favoriteTable);
+ $alreadyFavorite = false; // for favorite_anchor template
+ }
+ } elseif (isset($_REQUEST['add_favorite'])) {
+ if (! $alreadyFavorite) {
+ $numTables = count($favoriteInstance->getTables());
+ if ($numTables == $cfg['NumFavoriteTables']) {
+ $changes = false;
+ } else {
+ // Otherwise add to favorite list.
+ $favoriteInstance->add($this->db, $favoriteTable);
+ $alreadyFavorite = true; // for favorite_anchor template
+ }
+ }
+ }
+
+ $favoriteTables[$user] = $favoriteInstance->getTables();
+
+ $json = [];
+ $json['changes'] = $changes;
+ if (! $changes) {
+ $json['message'] = $this->template->render('components/error_message', [
+ 'msg' => __('Favorite List is full!'),
+ ]);
+ $this->response->addJSON($json);
+
+ return;
+ }
+
+ // Check if current table is already in favorite list.
+ $favoriteParams = [
+ 'db' => $this->db,
+ 'ajax_request' => true,
+ 'favorite_table' => $favoriteTable,
+ ($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true,
+ ];
+
+ $json['user'] = $user;
+ $json['favoriteTables'] = json_encode($favoriteTables);
+ $json['list'] = $favoriteInstance->getHtmlList();
+ $json['anchor'] = $this->template->render('database/structure/favorite_anchor', [
+ 'table_name_hash' => md5($favoriteTable),
+ 'db_table_name_hash' => md5($this->db . '.' . $favoriteTable),
+ 'fav_params' => $favoriteParams,
+ 'already_favorite' => $alreadyFavorite,
+ ]);
+
+ $this->response->addJSON($json);
+ }
+
+ /**
+ * Synchronize favorite tables
+ *
+ * @param RecentFavoriteTable $favoriteInstance Instance of this class
+ * @param string $user The user hash
+ * @param array $favoriteTables Existing favorites
+ *
+ * @return array
+ */
+ private function synchronizeFavoriteTables(
+ RecentFavoriteTable $favoriteInstance,
+ string $user,
+ array $favoriteTables
+ ): array {
+ $favoriteInstanceTables = $favoriteInstance->getTables();
+
+ if (
+ empty($favoriteInstanceTables)
+ && isset($favoriteTables[$user])
+ ) {
+ foreach ($favoriteTables[$user] as $key => $value) {
+ $favoriteInstance->add($value['db'], $value['table']);
+ }
+ }
+
+ $favoriteTables[$user] = $favoriteInstance->getTables();
+
+ $json = [
+ 'favoriteTables' => json_encode($favoriteTables),
+ 'list' => $favoriteInstance->getHtmlList(),
+ ];
+ $serverId = $GLOBALS['server'];
+ // Set flag when localStorage and pmadb(if present) are in sync.
+ $_SESSION['tmpval']['favorites_synced'][$serverId] = true;
+
+ return $json;
+ }
+
+ /**
+ * Function to check if a table is already in favorite list.
+ *
+ * @param string $currentTable current table
+ */
+ private function checkFavoriteTable(string $currentTable): bool
+ {
+ // ensure $_SESSION['tmpval']['favoriteTables'] is initialized
+ RecentFavoriteTable::getInstance('favorite');
+ $favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
+ foreach ($favoriteTables as $value) {
+ if ($value['db'] == $this->db && $value['table'] == $currentTable) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/RealRowCountController.php b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php
new file mode 100644
index 0000000000..1446140793
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/RealRowCountController.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Url;
+use PhpMyAdmin\Util;
+
+use function json_encode;
+
+/**
+ * Handles request for real row count on database level view page.
+ */
+final class RealRowCountController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ }
+
+ public function __invoke(): void
+ {
+ global $cfg, $db, $errorUrl;
+
+ $parameters = [
+ 'real_row_count_all' => $_REQUEST['real_row_count_all'] ?? null,
+ 'table' => $_REQUEST['table'] ?? null,
+ ];
+
+ Util::checkParameters(['db']);
+
+ $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
+ $errorUrl .= Url::getCommon(['db' => $db], '&');
+
+ if (! $this->hasDatabase() || ! $this->response->isAjax()) {
+ return;
+ }
+
+ [$tables] = Util::getDbInfo($this->db, '_structure');
+
+ // If there is a request to update all table's row count.
+ if (! isset($parameters['real_row_count_all'])) {
+ // Get the real row count for the table.
+ $realRowCount = (int) $this->dbi
+ ->getTable($this->db, (string) $parameters['table'])
+ ->getRealRowCountTable();
+ // Format the number.
+ $realRowCount = Util::formatNumber($realRowCount, 0);
+
+ $this->response->addJSON(['real_row_count' => $realRowCount]);
+
+ return;
+ }
+
+ // Array to store the results.
+ $realRowCountAll = [];
+ // Iterate over each table and fetch real row count.
+ foreach ($tables as $table) {
+ $rowCount = $this->dbi
+ ->getTable($this->db, $table['TABLE_NAME'])
+ ->getRealRowCountTable();
+ $realRowCountAll[] = [
+ 'table' => $table['TABLE_NAME'],
+ 'row_count' => $rowCount,
+ ];
+ }
+
+ $this->response->addJSON(['real_row_count_all' => json_encode($realRowCountAll)]);
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php b/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php
new file mode 100644
index 0000000000..2ac587aaa9
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php
@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Controllers\Database\StructureController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Util;
+
+use function count;
+use function mb_strlen;
+use function mb_substr;
+
+final class ReplacePrefixController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var StructureController */
+ private $structureController;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi, StructureController $structureController)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ $this->structureController = $structureController;
+ }
+
+ public function __invoke(): void
+ {
+ global $db, $message, $sql_query;
+
+ $selected = $_POST['selected'] ?? [];
+ $fromPrefix = $_POST['from_prefix'] ?? '';
+ $toPrefix = $_POST['to_prefix'] ?? '';
+
+ $sql_query = '';
+ $selectedCount = count($selected);
+
+ for ($i = 0; $i < $selectedCount; $i++) {
+ $current = $selected[$i];
+ $subFromPrefix = mb_substr($current, 0, mb_strlen((string) $fromPrefix));
+
+ if ($subFromPrefix === $fromPrefix) {
+ $newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix));
+ } else {
+ $newTableName = $current;
+ }
+
+ $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
+ . ' RENAME ' . Util::backquote($newTableName);
+
+ $sql_query .= $aQuery . ';' . "\n";
+ $this->dbi->selectDb($db);
+ $this->dbi->query($aQuery);
+ }
+
+ $message = Message::success();
+
+ if (empty($_POST['message'])) {
+ $_POST['message'] = $message;
+ }
+
+ ($this->structureController)();
+ }
+}
diff --git a/libraries/classes/Controllers/Database/Structure/ShowCreateController.php b/libraries/classes/Controllers/Database/Structure/ShowCreateController.php
new file mode 100644
index 0000000000..f148316e94
--- /dev/null
+++ b/libraries/classes/Controllers/Database/Structure/ShowCreateController.php
@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\AbstractController;
+use PhpMyAdmin\Core;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+
+use function __;
+
+final class ShowCreateController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param string $db
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $db, $dbi)
+ {
+ parent::__construct($response, $template, $db);
+ $this->dbi = $dbi;
+ }
+
+ public function __invoke(): void
+ {
+ $selected = $_POST['selected_tbl'] ?? [];
+
+ if (empty($selected)) {
+ $this->response->setRequestStatus(false);
+ $this->response->addJSON('message', __('No table selected.'));
+
+ return;
+ }
+
+ $tables = $this->getShowCreateTables($selected);
+
+ $showCreate = $this->template->render('database/structure/show_create', ['tables' => $tables]);
+
+ $this->response->addJSON('message', $showCreate);
+ }
+
+ /**
+ * @param string[] $selected Selected tables.
+ *
+ * @return array<string, array<int, array<string, string>>>
+ */
+ private function getShowCreateTables(array $selected): array
+ {
+ $tables = ['tables' => [], 'views' => []];
+
+ foreach ($selected as $table) {
+ $object = $this->dbi->getTable($this->db, $table);
+
+ $tables[$object->isView() ? 'views' : 'tables'][] = [
+ 'name' => Core::mimeDefaultFunction($table),
+ 'show_create' => Core::mimeDefaultFunction($object->showCreate()),
+ ];
+ }
+
+ return $tables;
+ }
+}
diff --git a/libraries/classes/Controllers/Database/StructureController.php b/libraries/classes/Controllers/Database/StructureController.php
index 00b65caeaf..3bbd1e5b70 100644
--- a/libraries/classes/Controllers/Database/StructureController.php
+++ b/libraries/classes/Controllers/Database/StructureController.php
@@ -7,12 +7,9 @@ namespace PhpMyAdmin\Controllers\Database;
use PhpMyAdmin\Charsets;
use PhpMyAdmin\CheckUserPrivileges;
use PhpMyAdmin\Config\PageSettings;
-use PhpMyAdmin\Core;
-use PhpMyAdmin\Database\CentralColumns;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\FlashMessages;
use PhpMyAdmin\Html\Generator;
-use PhpMyAdmin\Message;
use PhpMyAdmin\Operations;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Relation;
@@ -21,15 +18,11 @@ use PhpMyAdmin\Replication;
use PhpMyAdmin\ReplicationInfo;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Sanitize;
-use PhpMyAdmin\Sql;
use PhpMyAdmin\StorageEngine;
-use PhpMyAdmin\Table;
use PhpMyAdmin\Template;
use PhpMyAdmin\Tracker;
-use PhpMyAdmin\Transformations;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
-use PhpMyAdmin\Utils\ForeignKey;
use function __;
use function array_search;
@@ -39,15 +32,11 @@ use function htmlspecialchars;
use function implode;
use function in_array;
use function is_string;
-use function json_decode;
-use function json_encode;
use function max;
-use function mb_strlen;
use function mb_substr;
use function md5;
use function preg_match;
use function preg_quote;
-use function sha1;
use function sprintf;
use function str_replace;
use function strlen;
@@ -151,7 +140,7 @@ class StructureController extends AbstractController
$this->isShowStats = $isShowStats;
}
- public function index(): void
+ public function __invoke(): void
{
global $cfg, $db, $errorUrl;
@@ -235,198 +224,6 @@ class StructureController extends AbstractController
]);
}
- public function addRemoveFavoriteTablesAction(): void
- {
- global $cfg, $db, $errorUrl;
-
- $parameters = [
- 'favorite_table' => $_REQUEST['favorite_table'] ?? null,
- 'favoriteTables' => $_REQUEST['favoriteTables'] ?? null,
- 'sync_favorite_tables' => $_REQUEST['sync_favorite_tables'] ?? null,
- ];
-
- Util::checkParameters(['db']);
-
- $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
- $errorUrl .= Url::getCommon(['db' => $db], '&');
-
- if (! $this->hasDatabase() || ! $this->response->isAjax()) {
- return;
- }
-
- $favoriteInstance = RecentFavoriteTable::getInstance('favorite');
- if (isset($parameters['favoriteTables'])) {
- $favoriteTables = json_decode($parameters['favoriteTables'], true);
- } else {
- $favoriteTables = [];
- }
-
- // Required to keep each user's preferences separate.
- $user = sha1($cfg['Server']['user']);
-
- // Request for Synchronization of favorite tables.
- if (isset($parameters['sync_favorite_tables'])) {
- $cfgRelation = $this->relation->getRelationsParam();
- if ($cfgRelation['favoritework']) {
- $this->response->addJSON($this->synchronizeFavoriteTables(
- $favoriteInstance,
- $user,
- $favoriteTables
- ));
- }
-
- return;
- }
-
- $changes = true;
- $favoriteTable = $parameters['favorite_table'] ?? '';
- $alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
-
- if (isset($_REQUEST['remove_favorite'])) {
- if ($alreadyFavorite) {
- // If already in favorite list, remove it.
- $favoriteInstance->remove($this->db, $favoriteTable);
- $alreadyFavorite = false; // for favorite_anchor template
- }
- } elseif (isset($_REQUEST['add_favorite'])) {
- if (! $alreadyFavorite) {
- $numTables = count($favoriteInstance->getTables());
- if ($numTables == $cfg['NumFavoriteTables']) {
- $changes = false;
- } else {
- // Otherwise add to favorite list.
- $favoriteInstance->add($this->db, $favoriteTable);
- $alreadyFavorite = true; // for favorite_anchor template
- }
- }
- }
-
- $favoriteTables[$user] = $favoriteInstance->getTables();
-
- $json = [];
- $json['changes'] = $changes;
- if (! $changes) {
- $json['message'] = $this->template->render('components/error_message', [
- 'msg' => __('Favorite List is full!'),
- ]);
- $this->response->addJSON($json);
-
- return;
- }
-
- // Check if current table is already in favorite list.
- $favoriteParams = [
- 'db' => $this->db,
- 'ajax_request' => true,
- 'favorite_table' => $favoriteTable,
- ($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true,
- ];
-
- $json['user'] = $user;
- $json['favoriteTables'] = json_encode($favoriteTables);
- $json['list'] = $favoriteInstance->getHtmlList();
- $json['anchor'] = $this->template->render('database/structure/favorite_anchor', [
- 'table_name_hash' => md5($favoriteTable),
- 'db_table_name_hash' => md5($this->db . '.' . $favoriteTable),
- 'fav_params' => $favoriteParams,
- 'already_favorite' => $alreadyFavorite,
- ]);
-
- $this->response->addJSON($json);
- }
-
- /**
- * Handles request for real row count on database level view page.
- */
- public function handleRealRowCountRequestAction(): void
- {
- global $cfg, $db, $errorUrl;
-
- $parameters = [
- 'real_row_count_all' => $_REQUEST['real_row_count_all'] ?? null,
- 'table' => $_REQUEST['table'] ?? null,
- ];
-
- Util::checkParameters(['db']);
-
- $errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
- $errorUrl .= Url::getCommon(['db' => $db], '&');
-
- if (! $this->hasDatabase() || ! $this->response->isAjax()) {
- return;
- }
-
- // If there is a request to update all table's row count.
- if (! isset($parameters['real_row_count_all'])) {
- // Get the real row count for the table.
- $realRowCount = (int) $this->dbi
- ->getTable($this->db, (string) $parameters['table'])
- ->getRealRowCountTable();
- // Format the number.
- $realRowCount = Util::formatNumber($realRowCount, 0);
-
- $this->response->addJSON(['real_row_count' => $realRowCount]);
-
- return;
- }
-
- // Array to store the results.
- $realRowCountAll = [];
- // Iterate over each table and fetch real row count.
- foreach ($this->tables as $table) {
- $rowCount = $this->dbi
- ->getTable($this->db, $table['TABLE_NAME'])
- ->getRealRowCountTable();
- $realRowCountAll[] = [
- 'table' => $table['TABLE_NAME'],
- 'row_count' => $rowCount,
- ];
- }
-
- $this->response->addJSON(['real_row_count_all' => json_encode($realRowCountAll)]);
- }
-
- public function copyTable(): void
- {
- global $db, $message;
-
- $selected = $_POST['selected'] ?? [];
- $targetDb = $_POST['target_db'] ?? null;
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- Table::moveCopy(
- $db,
- $selected[$i],
- $targetDb,
- $selected[$i],
- $_POST['what'],
- false,
- 'one_table',
- isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
- );
-
- if (empty($_POST['adjust_privileges'])) {
- continue;
- }
-
- $this->operations->adjustPrivilegesCopyTable(
- $db,
- $selected[$i],
- $targetDb,
- $selected[$i]
- );
- }
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- $this->index();
- }
-
/**
* @param array $replicaInfo
*/
@@ -893,44 +690,6 @@ class StructureController extends AbstractController
}
/**
- * Synchronize favorite tables
- *
- * @param RecentFavoriteTable $favoriteInstance Instance of this class
- * @param string $user The user hash
- * @param array $favoriteTables Existing favorites
- *
- * @return array
- */
- protected function synchronizeFavoriteTables(
- RecentFavoriteTable $favoriteInstance,
- string $user,
- array $favoriteTables
- ): array {
- $favoriteInstanceTables = $favoriteInstance->getTables();
-
- if (
- empty($favoriteInstanceTables)
- && isset($favoriteTables[$user])
- ) {
- foreach ($favoriteTables[$user] as $key => $value) {
- $favoriteInstance->add($value['db'], $value['table']);
- }
- }
-
- $favoriteTables[$user] = $favoriteInstance->getTables();
-
- $json = [
- 'favoriteTables' => json_encode($favoriteTables),
- 'list' => $favoriteInstance->getHtmlList(),
- ];
- $serverId = $GLOBALS['server'];
- // Set flag when localStorage and pmadb(if present) are in sync.
- $_SESSION['tmpval']['favorites_synced'][$serverId] = true;
-
- return $json;
- }
-
- /**
* Function to check if a table is already in favorite list.
*
* @param string $currentTable current table
@@ -1240,524 +999,4 @@ class StructureController extends AbstractController
$sumSize,
];
}
-
- public function showCreate(): void
- {
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $tables = $this->getShowCreateTables($selected);
-
- $showCreate = $this->template->render('database/structure/show_create', ['tables' => $tables]);
-
- $this->response->addJSON('message', $showCreate);
- }
-
- /**
- * @param string[] $selected Selected tables.
- *
- * @return array<string, array<int, array<string, string>>>
- */
- private function getShowCreateTables(array $selected): array
- {
- $tables = ['tables' => [], 'views' => []];
-
- foreach ($selected as $table) {
- $object = $this->dbi->getTable($this->db, $table);
-
- $tables[$object->isView() ? 'views' : 'tables'][] = [
- 'name' => Core::mimeDefaultFunction($table),
- 'show_create' => Core::mimeDefaultFunction($object->showCreate()),
- ];
- }
-
- return $tables;
- }
-
- public function copyForm(): void
- {
- global $db, $dblist;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $urlParams = ['db' => $db];
- foreach ($selected as $selectedValue) {
- $urlParams['selected'][] = $selectedValue;
- }
-
- $databasesList = $dblist->databases;
- foreach ($databasesList as $key => $databaseName) {
- if ($databaseName == $db) {
- $databasesList->offsetUnset($key);
- break;
- }
- }
-
- $this->response->disable();
- $this->render('database/structure/copy_form', [
- 'url_params' => $urlParams,
- 'options' => $databasesList->getList(),
- ]);
- }
-
- public function centralColumnsAdd(): void
- {
- global $message;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $centralColumns = new CentralColumns($this->dbi);
- $error = $centralColumns->syncUniqueColumns($selected);
-
- $message = $error instanceof Message ? $error : Message::success(__('Success!'));
-
- unset($_POST['submit_mult']);
-
- $this->index();
- }
-
- public function centralColumnsMakeConsistent(): void
- {
- global $db, $message;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $centralColumns = new CentralColumns($this->dbi);
- $error = $centralColumns->makeConsistentWithList($db, $selected);
-
- $message = $error instanceof Message ? $error : Message::success(__('Success!'));
-
- unset($_POST['submit_mult']);
-
- $this->index();
- }
-
- public function centralColumnsRemove(): void
- {
- global $message;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $centralColumns = new CentralColumns($this->dbi);
- $error = $centralColumns->deleteColumnsFromList($_POST['db'], $selected);
-
- $message = $error instanceof Message ? $error : Message::success(__('Success!'));
-
- unset($_POST['submit_mult']);
-
- $this->index();
- }
-
- public function addPrefix(): void
- {
- global $db;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $params = ['db' => $db];
- foreach ($selected as $selectedValue) {
- $params['selected'][] = $selectedValue;
- }
-
- $this->response->disable();
- $this->render('database/structure/add_prefix', ['url_params' => $params]);
- }
-
- public function changePrefixForm(): void
- {
- global $db;
-
- $selected = $_POST['selected_tbl'] ?? [];
- $submitMult = $_POST['submit_mult'] ?? '';
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $route = '/database/structure/replace-prefix';
- if ($submitMult === 'copy_tbl_change_prefix') {
- $route = '/database/structure/copy-table-with-prefix';
- }
-
- $urlParams = ['db' => $db];
- foreach ($selected as $selectedValue) {
- $urlParams['selected'][] = $selectedValue;
- }
-
- $this->response->disable();
- $this->render('database/structure/change_prefix_form', [
- 'route' => $route,
- 'url_params' => $urlParams,
- ]);
- }
-
- public function dropForm(): void
- {
- global $db;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $views = $this->dbi->getVirtualTables($db);
-
- $fullQueryViews = '';
- $fullQuery = '';
-
- foreach ($selected as $selectedValue) {
- $current = $selectedValue;
- if (! empty($views) && in_array($current, $views)) {
- $fullQueryViews .= (empty($fullQueryViews) ? 'DROP VIEW ' : ', ')
- . Util::backquote(htmlspecialchars($current));
- } else {
- $fullQuery .= (empty($fullQuery) ? 'DROP TABLE ' : ', ')
- . Util::backquote(htmlspecialchars($current));
- }
- }
-
- if (! empty($fullQuery)) {
- $fullQuery .= ';<br>' . "\n";
- }
-
- if (! empty($fullQueryViews)) {
- $fullQuery .= $fullQueryViews . ';<br>' . "\n";
- }
-
- $urlParams = ['db' => $db];
- foreach ($selected as $selectedValue) {
- $urlParams['selected'][] = $selectedValue;
- }
-
- foreach ($views as $current) {
- $urlParams['views'][] = $current;
- }
-
- $this->render('database/structure/drop_form', [
- 'url_params' => $urlParams,
- 'full_query' => $fullQuery,
- 'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
- ]);
- }
-
- public function emptyForm(): void
- {
- global $db;
-
- $selected = $_POST['selected_tbl'] ?? [];
-
- if (empty($selected)) {
- $this->response->setRequestStatus(false);
- $this->response->addJSON('message', __('No table selected.'));
-
- return;
- }
-
- $fullQuery = '';
- $urlParams = ['db' => $db];
-
- foreach ($selected as $selectedValue) {
- $fullQuery .= 'TRUNCATE ';
- $fullQuery .= Util::backquote(htmlspecialchars($selectedValue)) . ';<br>';
- $urlParams['selected'][] = $selectedValue;
- }
-
- $this->render('database/structure/empty_form', [
- 'url_params' => $urlParams,
- 'full_query' => $fullQuery,
- 'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
- ]);
- }
-
- public function dropTable(): void
- {
- global $db, $message, $reload, $sql_query;
-
- $reload = $_POST['reload'] ?? $reload ?? null;
- $multBtn = $_POST['mult_btn'] ?? '';
- $selected = $_POST['selected'] ?? [];
-
- $views = $this->dbi->getVirtualTables($db);
-
- if ($multBtn !== __('Yes')) {
- $message = Message::success(__('No change'));
-
- if (empty($_POST['message'])) {
- $_POST['message'] = Message::success();
- }
-
- unset($_POST['mult_btn']);
-
- $this->index();
-
- return;
- }
-
- $defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
- $sql_query = '';
- $sqlQueryViews = '';
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- $this->relationCleanup->table($db, $selected[$i]);
- $current = $selected[$i];
-
- if (! empty($views) && in_array($current, $views)) {
- $sqlQueryViews .= (empty($sqlQueryViews) ? 'DROP VIEW ' : ', ') . Util::backquote($current);
- } else {
- $sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') . Util::backquote($current);
- }
-
- $reload = 1;
- }
-
- if (! empty($sql_query)) {
- $sql_query .= ';';
- } elseif (! empty($sqlQueryViews)) {
- $sql_query = $sqlQueryViews . ';';
- unset($sqlQueryViews);
- }
-
- // Unset cache values for tables count, issue #14205
- if (isset($_SESSION['tmpval'])) {
- if (isset($_SESSION['tmpval']['table_limit_offset'])) {
- unset($_SESSION['tmpval']['table_limit_offset']);
- }
-
- if (isset($_SESSION['tmpval']['table_limit_offset_db'])) {
- unset($_SESSION['tmpval']['table_limit_offset_db']);
- }
- }
-
- $this->dbi->selectDb($db);
- $result = $this->dbi->tryQuery($sql_query);
-
- if ($result && ! empty($sqlQueryViews)) {
- $sql_query .= ' ' . $sqlQueryViews . ';';
- $result = $this->dbi->tryQuery($sqlQueryViews);
- unset($sqlQueryViews);
- }
-
- if (! $result) {
- $message = Message::error((string) $this->dbi->getError());
- }
-
- ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- unset($_POST['mult_btn']);
-
- $this->index();
- }
-
- public function emptyTable(): void
- {
- global $db, $table, $message, $sql_query;
-
- $multBtn = $_POST['mult_btn'] ?? '';
- $selected = $_POST['selected'] ?? [];
-
- if ($multBtn !== __('Yes')) {
- $this->flash->addMessage('success', __('No change'));
- $this->redirect('/database/structure', ['db' => $db]);
-
- return;
- }
-
- $defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
-
- $sql_query = '';
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- $aQuery = 'TRUNCATE ';
- $aQuery .= Util::backquote($selected[$i]);
-
- $sql_query .= $aQuery . ';' . "\n";
- $this->dbi->selectDb($db);
- $this->dbi->query($aQuery);
- }
-
- if (! empty($_REQUEST['pos'])) {
- $sql = new Sql(
- $this->dbi,
- $this->relation,
- $this->relationCleanup,
- $this->operations,
- new Transformations(),
- $this->template
- );
-
- $_REQUEST['pos'] = $sql->calculatePosForLastPage($db, $table, $_REQUEST['pos']);
- }
-
- ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- unset($_POST['mult_btn']);
-
- $this->index();
- }
-
- public function addPrefixTable(): void
- {
- global $db, $message, $sql_query;
-
- $selected = $_POST['selected'] ?? [];
-
- $sql_query = '';
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- $newTableName = $_POST['add_prefix'] . $selected[$i];
- $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
- . ' RENAME ' . Util::backquote($newTableName);
-
- $sql_query .= $aQuery . ';' . "\n";
- $this->dbi->selectDb($db);
- $this->dbi->query($aQuery);
- }
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- $this->index();
- }
-
- public function replacePrefix(): void
- {
- global $db, $message, $sql_query;
-
- $selected = $_POST['selected'] ?? [];
- $fromPrefix = $_POST['from_prefix'] ?? '';
- $toPrefix = $_POST['to_prefix'] ?? '';
-
- $sql_query = '';
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- $current = $selected[$i];
- $subFromPrefix = mb_substr($current, 0, mb_strlen((string) $fromPrefix));
-
- if ($subFromPrefix === $fromPrefix) {
- $newTableName = $toPrefix . mb_substr(
- $current,
- mb_strlen((string) $fromPrefix)
- );
- } else {
- $newTableName = $current;
- }
-
- $aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
- . ' RENAME ' . Util::backquote($newTableName);
-
- $sql_query .= $aQuery . ';' . "\n";
- $this->dbi->selectDb($db);
- $this->dbi->query($aQuery);
- }
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- $this->index();
- }
-
- public function copyTableWithPrefix(): void
- {
- global $db, $message;
-
- $selected = $_POST['selected'] ?? [];
- $fromPrefix = $_POST['from_prefix'] ?? null;
- $toPrefix = $_POST['to_prefix'] ?? null;
-
- $selectedCount = count($selected);
-
- for ($i = 0; $i < $selectedCount; $i++) {
- $current = $selected[$i];
- $newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix));
-
- Table::moveCopy(
- $db,
- $current,
- $db,
- $newTableName,
- 'data',
- false,
- 'one_table',
- isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
- );
- }
-
- $message = Message::success();
-
- if (empty($_POST['message'])) {
- $_POST['message'] = $message;
- }
-
- $this->index();
- }
}
diff --git a/libraries/classes/Controllers/Export/CheckTimeOutController.php b/libraries/classes/Controllers/Export/CheckTimeOutController.php
new file mode 100644
index 0000000000..10da315083
--- /dev/null
+++ b/libraries/classes/Controllers/Export/CheckTimeOutController.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Export;
+
+use PhpMyAdmin\Controllers\AbstractController;
+
+final class CheckTimeOutController extends AbstractController
+{
+ public function __invoke(): void
+ {
+ $this->response->setAjax(true);
+
+ if (isset($_SESSION['pma_export_error'])) {
+ unset($_SESSION['pma_export_error']);
+ $this->response->addJSON('message', 'timeout');
+
+ return;
+ }
+
+ $this->response->addJSON('message', 'success');
+ }
+}
diff --git a/libraries/classes/Controllers/Export/ExportController.php b/libraries/classes/Controllers/Export/ExportController.php
index 2c514890e8..78f28a7514 100644
--- a/libraries/classes/Controllers/Export/ExportController.php
+++ b/libraries/classes/Controllers/Export/ExportController.php
@@ -718,18 +718,4 @@ final class ExportController extends AbstractController
echo $this->export->dumpBuffer;
}
-
- public function checkTimeOut(): void
- {
- $this->response->setAjax(true);
-
- if (isset($_SESSION['pma_export_error'])) {
- unset($_SESSION['pma_export_error']);
- $this->response->addJSON('message', 'timeout');
-
- return;
- }
-
- $this->response->addJSON('message', 'success');
- }
}
diff --git a/libraries/classes/Controllers/Server/Databases/CreateController.php b/libraries/classes/Controllers/Server/Databases/CreateController.php
new file mode 100644
index 0000000000..0c6b1442b0
--- /dev/null
+++ b/libraries/classes/Controllers/Server/Databases/CreateController.php
@@ -0,0 +1,119 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Server\Databases;
+
+use PhpMyAdmin\Charsets;
+use PhpMyAdmin\Controllers\AbstractController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Html\Generator;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Url;
+use PhpMyAdmin\Util;
+
+use function __;
+use function array_key_exists;
+use function explode;
+use function mb_strlen;
+use function mb_strtolower;
+use function str_contains;
+
+final class CreateController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct($response, Template $template, $dbi)
+ {
+ parent::__construct($response, $template);
+ $this->dbi = $dbi;
+ }
+
+ public function __invoke(): void
+ {
+ global $cfg, $db;
+
+ $params = [
+ 'new_db' => $_POST['new_db'] ?? null,
+ 'db_collation' => $_POST['db_collation'] ?? null,
+ ];
+
+ if (! isset($params['new_db']) || mb_strlen($params['new_db']) === 0 || ! $this->response->isAjax()) {
+ $this->response->addJSON(['message' => Message::error()]);
+
+ return;
+ }
+
+ // lower_case_table_names=1 `DB` becomes `db`
+ if ($this->dbi->getLowerCaseNames() === '1') {
+ $params['new_db'] = mb_strtolower(
+ $params['new_db']
+ );
+ }
+
+ /**
+ * Builds and executes the db creation sql query
+ */
+ $sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']);
+ if (! empty($params['db_collation'])) {
+ [$databaseCharset] = explode('_', $params['db_collation']);
+ $charsets = Charsets::getCharsets(
+ $this->dbi,
+ $cfg['Server']['DisableIS']
+ );
+ $collations = Charsets::getCollations(
+ $this->dbi,
+ $cfg['Server']['DisableIS']
+ );
+ if (
+ array_key_exists($databaseCharset, $charsets)
+ && array_key_exists($params['db_collation'], $collations[$databaseCharset])
+ ) {
+ $sqlQuery .= ' DEFAULT'
+ . Util::getCharsetQueryPart($params['db_collation']);
+ }
+ }
+
+ $sqlQuery .= ';';
+
+ $result = $this->dbi->tryQuery($sqlQuery);
+
+ if (! $result) {
+ // avoid displaying the not-created db name in header or navi panel
+ $db = '';
+
+ $message = Message::rawError((string) $this->dbi->getError());
+ $json = ['message' => $message];
+
+ $this->response->setRequestStatus(false);
+ } else {
+ $db = $params['new_db'];
+
+ $message = Message::success(__('Database %1$s has been created.'));
+ $message->addParam($params['new_db']);
+
+ $scriptName = Util::getScriptNameForOption(
+ $cfg['DefaultTabDatabase'],
+ 'database'
+ );
+
+ $json = [
+ 'message' => $message,
+ 'sql_query' => Generator::getMessage('', $sqlQuery, 'success'),
+ 'url' => $scriptName . Url::getCommon(
+ ['db' => $params['new_db']],
+ ! str_contains($scriptName, '?') ? '?' : '&'
+ ),
+ ];
+ }
+
+ $this->response->addJSON($json);
+ }
+}
diff --git a/libraries/classes/Controllers/Server/Databases/DestroyController.php b/libraries/classes/Controllers/Server/Databases/DestroyController.php
new file mode 100644
index 0000000000..4f7d50cf0f
--- /dev/null
+++ b/libraries/classes/Controllers/Server/Databases/DestroyController.php
@@ -0,0 +1,122 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Controllers\Server\Databases;
+
+use PhpMyAdmin\Controllers\AbstractController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Message;
+use PhpMyAdmin\RelationCleanup;
+use PhpMyAdmin\ResponseRenderer;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Url;
+use PhpMyAdmin\Util;
+
+use function __;
+use function _ngettext;
+use function count;
+
+final class DestroyController extends AbstractController
+{
+ /** @var DatabaseInterface */
+ private $dbi;
+
+ /** @var Transformations */
+ private $transformations;
+
+ /** @var RelationCleanup */
+ private $relationCleanup;
+
+ /**
+ * @param ResponseRenderer $response
+ * @param DatabaseInterface $dbi
+ */
+ public function __construct(
+ $response,
+ Template $template,
+ $dbi,
+ Transformations $transformations,
+ RelationCleanup $relationCleanup
+ ) {
+ parent::__construct($response, $template);
+ $this->dbi = $dbi;
+ $this->transformations = $transformations;
+ $this->relationCleanup = $relationCleanup;
+ }
+
+ public function __invoke(): void
+ {
+ global $selected, $errorUrl, $cfg, $dblist, $reload;
+
+ $params = [
+ 'drop_selected_dbs' => $_POST['drop_selected_dbs'] ?? null,
+ 'selected_dbs' => $_POST['selected_dbs'] ?? null,
+ ];
+ /** @var Message|int $message */
+ $message = -1;
+
+ if (
+ ! isset($params['drop_selected_dbs'])
+ || ! $this->response->isAjax()
+ || (! $this->dbi->isSuperUser() && ! $cfg['AllowUserDropDatabase'])
+ ) {
+ $message = Message::error();
+ $json = ['message' => $message];
+ $this->response->setRequestStatus($message->isSuccess());
+ $this->response->addJSON($json);
+
+ return;
+ }
+
+ if (! isset($params['selected_dbs'])) {
+ $message = Message::error(__('No databases selected.'));
+ $json = ['message' => $message];
+ $this->response->setRequestStatus($message->isSuccess());
+ $this->response->addJSON($json);
+
+ return;
+ }
+
+ $errorUrl = Url::getFromRoute('/server/databases');
+ $selected = $_POST['selected_dbs'];
+ $rebuildDatabaseList = false;
+ $sqlQuery = '';
+ $numberOfDatabases = count($selected);
+
+ for ($i = 0; $i < $numberOfDatabases; $i++) {
+ $this->relationCleanup->database($selected[$i]);
+ $aQuery = 'DROP DATABASE ' . Util::backquote($selected[$i]);
+ $reload = true;
+ $rebuildDatabaseList = true;
+
+ $sqlQuery .= $aQuery . ';' . "\n";
+ $this->dbi->query($aQuery);
+ $this->transformations->clear($selected[$i]);
+ }
+
+ if ($rebuildDatabaseList) {
+ $dblist->databases->build();
+ }
+
+ if ($message === -1) { // no error message
+ $message = Message::success(
+ _ngettext(
+ '%1$d database has been dropped successfully.',
+ '%1$d databases have been dropped successfully.',
+ $numberOfDatabases
+ )
+ );
+ $message->addParam($numberOfDatabases);
+ }
+
+ $json = [];
+ if ($message instanceof Message) {
+ $json = ['message' => $message];
+ $this->response->setRequestStatus($message->isSuccess());
+ }
+
+ $this->response->addJSON($json);
+ }
+}
diff --git a/libraries/classes/Controllers/Server/DatabasesController.php b/libraries/classes/Controllers/Server/DatabasesController.php
index 9069110373..ad5d353971 100644
--- a/libraries/classes/Controllers/Server/DatabasesController.php
+++ b/libraries/classes/Controllers/Server/DatabasesController.php
@@ -10,8 +10,6 @@ use PhpMyAdmin\Charsets\Collation;
use PhpMyAdmin\CheckUserPrivileges;
use PhpMyAdmin\Controllers\AbstractController;
use PhpMyAdmin\DatabaseInterface;
-use PhpMyAdmin\Html\Generator;
-use PhpMyAdmin\Message;
use PhpMyAdmin\Query\Utilities;
use PhpMyAdmin\RelationCleanup;
use PhpMyAdmin\ReplicationInfo;
@@ -22,14 +20,10 @@ use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use function __;
-use function _ngettext;
-use function array_key_exists;
use function array_keys;
use function array_search;
use function count;
-use function explode;
use function in_array;
-use function mb_strlen;
use function mb_strtolower;
use function str_contains;
use function strlen;
@@ -86,7 +80,7 @@ class DatabasesController extends AbstractController
$checkUserPrivileges->getPrivileges();
}
- public function index(): void
+ public function __invoke(): void
{
global $cfg, $server, $dblist, $is_create_db_priv;
global $db_to_create, $text_dir, $errorUrl;
@@ -187,164 +181,6 @@ class DatabasesController extends AbstractController
]);
}
- public function create(): void
- {
- global $cfg, $db;
-
- $params = [
- 'new_db' => $_POST['new_db'] ?? null,
- 'db_collation' => $_POST['db_collation'] ?? null,
- ];
-
- if (! isset($params['new_db']) || mb_strlen($params['new_db']) === 0 || ! $this->response->isAjax()) {
- $this->response->addJSON(['message' => Message::error()]);
-
- return;
- }
-
- // lower_case_table_names=1 `DB` becomes `db`
- if ($this->dbi->getLowerCaseNames() === '1') {
- $params['new_db'] = mb_strtolower(
- $params['new_db']
- );
- }
-
- /**
- * Builds and executes the db creation sql query
- */
- $sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']);
- if (! empty($params['db_collation'])) {
- [$databaseCharset] = explode('_', $params['db_collation']);
- $charsets = Charsets::getCharsets(
- $this->dbi,
- $cfg['Server']['DisableIS']
- );
- $collations = Charsets::getCollations(
- $this->dbi,
- $cfg['Server']['DisableIS']
- );
- if (
- array_key_exists($databaseCharset, $charsets)
- && array_key_exists($params['db_collation'], $collations[$databaseCharset])
- ) {
- $sqlQuery .= ' DEFAULT'
- . Util::getCharsetQueryPart($params['db_collation']);
- }
- }
-
- $sqlQuery .= ';';
-
- $result = $this->dbi->tryQuery($sqlQuery);
-
- if (! $result) {
- // avoid displaying the not-created db name in header or navi panel
- $db = '';
-
- $message = Message::rawError((string) $this->dbi->getError());
- $json = ['message' => $message];
-
- $this->response->setRequestStatus(false);
- } else {
- $db = $params['new_db'];
-
- $message = Message::success(__('Database %1$s has been created.'));
- $message->addParam($params['new_db']);
-
- $scriptName = Util::getScriptNameForOption(
- $cfg['DefaultTabDatabase'],
- 'database'
- );
-
- $json = [
- 'message' => $message,
- 'sql_query' => Generator::getMessage('', $sqlQuery, 'success'),
- 'url' => $scriptName . Url::getCommon(
- ['db' => $params['new_db']],
- ! str_contains($scriptName, '?') ? '?' : '&'
- ),
- ];
- }
-
- $this->response->addJSON($json);
- }
-
- /**
- * Handles dropping multiple databases
- */
- public function destroy(): void
- {
- global $selected, $errorUrl, $cfg, $dblist, $reload;
-
- $params = [
- 'drop_selected_dbs' => $_POST['drop_selected_dbs'] ?? null,
- 'selected_dbs' => $_POST['selected_dbs'] ?? null,
- ];
- /** @var Message|int $message */
- $message = -1;
-
- if (
- ! isset($params['drop_selected_dbs'])
- || ! $this->response->isAjax()
- || (! $this->dbi->isSuperUser() && ! $cfg['AllowUserDropDatabase'])
- ) {
- $message = Message::error();
- $json = ['message' => $message];
- $this->response->setRequestStatus($message->isSuccess());
- $this->response->addJSON($json);
-
- return;
- }
-
- if (! isset($params['selected_dbs'])) {
- $message = Message::error(__('No databases selected.'));
- $json = ['message' => $message];
- $this->response->setRequestStatus($message->isSuccess());
- $this->response->addJSON($json);
-
- return;
- }
-
- $errorUrl = Url::getFromRoute('/server/databases');
- $selected = $_POST['selected_dbs'];
- $rebuildDatabaseList = false;
- $sqlQuery = '';
- $numberOfDatabases = count($selected);
-
- for ($i = 0; $i < $numberOfDatabases; $i++) {
- $this->relationCleanup->database($selected[$i]);
- $aQuery = 'DROP DATABASE ' . Util::backquote($selected[$i]);
- $reload = true;
- $rebuildDatabaseList = true;
-
- $sqlQuery .= $aQuery . ';' . "\n";
- $this->dbi->query($aQuery);
- $this->transformations->clear($selected[$i]);
- }
-
- if ($rebuildDatabaseList) {
- $dblist->databases->build();
- }
-
- if ($message === -1) { // no error message
- $message = Message::success(
- _ngettext(
- '%1$d database has been dropped successfully.',
- '%1$d databases have been dropped successfully.',
- $numberOfDatabases
- )
- );
- $message->addParam($numberOfDatabases);
- }
-
- $json = [];
- if ($message instanceof Message) {
- $json = ['message' => $message];
- $this->response->setRequestStatus($message->isSuccess());
- }
-
- $this->response->addJSON($json);
- }
-
/**
* Extracts parameters sort order and sort by
*
diff --git a/libraries/routes.php b/libraries/routes.php
index 3acb0f8633..6a3f993d0d 100644
--- a/libraries/routes.php
+++ b/libraries/routes.php
@@ -20,6 +20,7 @@ use PhpMyAdmin\Controllers\Database\ImportController as DatabaseImportController
use PhpMyAdmin\Controllers\Database\MultiTableQuery\QueryController;
use PhpMyAdmin\Controllers\Database\MultiTableQuery\TablesController as MultiTableQueryTablesController;
use PhpMyAdmin\Controllers\Database\MultiTableQueryController;
+use PhpMyAdmin\Controllers\Database\Operations\CollationController;
use PhpMyAdmin\Controllers\Database\OperationsController;
use PhpMyAdmin\Controllers\Database\QueryByExampleController;
use PhpMyAdmin\Controllers\Database\RoutinesController;
@@ -27,11 +28,13 @@ use PhpMyAdmin\Controllers\Database\SearchController;
use PhpMyAdmin\Controllers\Database\SqlAutoCompleteController;
use PhpMyAdmin\Controllers\Database\SqlController as DatabaseSqlController;
use PhpMyAdmin\Controllers\Database\SqlFormatController;
+use PhpMyAdmin\Controllers\Database\Structure;
use PhpMyAdmin\Controllers\Database\StructureController;
use PhpMyAdmin\Controllers\Database\TrackingController;
use PhpMyAdmin\Controllers\Database\TriggersController;
use PhpMyAdmin\Controllers\DatabaseController;
use PhpMyAdmin\Controllers\ErrorReportController;
+use PhpMyAdmin\Controllers\Export\CheckTimeOutController;
use PhpMyAdmin\Controllers\Export\ExportController;
use PhpMyAdmin\Controllers\Export\TablesController;
use PhpMyAdmin\Controllers\Export\Template\CreateController as TemplateCreateController;
@@ -61,6 +64,8 @@ use PhpMyAdmin\Controllers\RecentTablesListController;
use PhpMyAdmin\Controllers\SchemaExportController;
use PhpMyAdmin\Controllers\Server\BinlogController;
use PhpMyAdmin\Controllers\Server\CollationsController;
+use PhpMyAdmin\Controllers\Server\Databases\CreateController as DatabasesCreateController;
+use PhpMyAdmin\Controllers\Server\Databases\DestroyController;
use PhpMyAdmin\Controllers\Server\DatabasesController;
use PhpMyAdmin\Controllers\Server\EnginesController;
use PhpMyAdmin\Controllers\Server\ExportController as ServerExportController;
@@ -145,8 +150,8 @@ return static function (RouteCollector $routes): void {
$routes->post('/query', QueryController::class);
});
$routes->addGroup('/operations', static function (RouteCollector $routes): void {
- $routes->addRoute(['GET', 'POST'], '', [OperationsController::class, 'index']);
- $routes->post('/collation', [OperationsController::class, 'collation']);
+ $routes->addRoute(['GET', 'POST'], '', OperationsController::class);
+ $routes->post('/collation', CollationController::class);
});
$routes->addRoute(['GET', 'POST'], '/qbe', QueryByExampleController::class);
$routes->addRoute(['GET', 'POST'], '/routines', RoutinesController::class);
@@ -157,33 +162,24 @@ return static function (RouteCollector $routes): void {
$routes->post('/format', SqlFormatController::class);
});
$routes->addGroup('/structure', static function (RouteCollector $routes): void {
- $routes->addRoute(['GET', 'POST'], '', [StructureController::class, 'index']);
- $routes->post('/add-prefix', [StructureController::class, 'addPrefix']);
- $routes->post('/add-prefix-table', [StructureController::class, 'addPrefixTable']);
- $routes->post('/central-columns-add', [StructureController::class, 'centralColumnsAdd']);
- $routes->post('/central-columns-make-consistent', [
- StructureController::class,
- 'centralColumnsMakeConsistent',
- ]);
- $routes->post('/central-columns-remove', [StructureController::class, 'centralColumnsRemove']);
- $routes->post('/change-prefix-form', [StructureController::class, 'changePrefixForm']);
- $routes->post('/copy-form', [StructureController::class, 'copyForm']);
- $routes->post('/copy-table', [StructureController::class, 'copyTable']);
- $routes->post('/copy-table-with-prefix', [StructureController::class, 'copyTableWithPrefix']);
- $routes->post('/drop-form', [StructureController::class, 'dropForm']);
- $routes->post('/drop-table', [StructureController::class, 'dropTable']);
- $routes->post('/empty-form', [StructureController::class, 'emptyForm']);
- $routes->post('/empty-table', [StructureController::class, 'emptyTable']);
- $routes->addRoute(['GET', 'POST'], '/favorite-table', [
- StructureController::class,
- 'addRemoveFavoriteTablesAction',
- ]);
- $routes->addRoute(['GET', 'POST'], '/real-row-count', [
- StructureController::class,
- 'handleRealRowCountRequestAction',
- ]);
- $routes->post('/replace-prefix', [StructureController::class, 'replacePrefix']);
- $routes->post('/show-create', [StructureController::class, 'showCreate']);
+ $routes->addRoute(['GET', 'POST'], '', StructureController::class);
+ $routes->post('/add-prefix', Structure\AddPrefixController::class);
+ $routes->post('/add-prefix-table', Structure\AddPrefixTableController::class);
+ $routes->post('/central-columns-add', Structure\CentralColumns\AddController::class);
+ $routes->post('/central-columns-make-consistent', Structure\CentralColumns\MakeConsistentController::class);
+ $routes->post('/central-columns-remove', Structure\CentralColumns\RemoveController::class);
+ $routes->post('/change-prefix-form', Structure\ChangePrefixFormController::class);
+ $routes->post('/copy-form', Structure\CopyFormController::class);
+ $routes->post('/copy-table', Structure\CopyTableController::class);
+ $routes->post('/copy-table-with-prefix', Structure\CopyTableWithPrefixController::class);
+ $routes->post('/drop-form', Structure\DropFormController::class);
+ $routes->post('/drop-table', Structure\DropTableController::class);
+ $routes->post('/empty-form', Structure\EmptyFormController::class);
+ $routes->post('/empty-table', Structure\EmptyTableController::class);
+ $routes->addRoute(['GET', 'POST'], '/favorite-table', Structure\FavoriteTableController::class);
+ $routes->addRoute(['GET', 'POST'], '/real-row-count', Structure\RealRowCountController::class);
+ $routes->post('/replace-prefix', Structure\ReplacePrefixController::class);
+ $routes->post('/show-create', Structure\ShowCreateController::class);
});
$routes->addRoute(['GET', 'POST'], '/tracking', TrackingController::class);
$routes->addRoute(['GET', 'POST'], '/triggers', TriggersController::class);
@@ -192,7 +188,7 @@ return static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/error-report', ErrorReportController::class);
$routes->addGroup('/export', static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '', ExportController::class);
- $routes->get('/check-time-out', [ExportController::class, 'checkTimeOut']);
+ $routes->get('/check-time-out', CheckTimeOutController::class);
$routes->post('/tables', TablesController::class);
$routes->addGroup('/template', static function (RouteCollector $routes): void {
$routes->post('/create', TemplateCreateController::class);
@@ -227,9 +223,9 @@ return static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/binlog', BinlogController::class);
$routes->get('/collations', CollationsController::class);
$routes->addGroup('/databases', static function (RouteCollector $routes): void {
- $routes->addRoute(['GET', 'POST'], '', [DatabasesController::class, 'index']);
- $routes->post('/create', [DatabasesController::class, 'create']);
- $routes->post('/destroy', [DatabasesController::class, 'destroy']);
+ $routes->addRoute(['GET', 'POST'], '', DatabasesController::class);
+ $routes->post('/create', DatabasesCreateController::class);
+ $routes->post('/destroy', DestroyController::class);
});
$routes->addGroup('/engines', static function (RouteCollector $routes): void {
$routes->get('', [EnginesController::class, 'index']);
diff --git a/libraries/services_controllers.php b/libraries/services_controllers.php
index b6ae3c6ead..1d23024e1e 100644
--- a/libraries/services_controllers.php
+++ b/libraries/services_controllers.php
@@ -152,6 +152,16 @@ return [
'$dbi' => '@dbi',
],
],
+ PhpMyAdmin\Controllers\Database\Operations\CollationController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Operations\CollationController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$operations' => '@operations',
+ '$dbi' => '@dbi',
+ ],
+ ],
PhpMyAdmin\Controllers\Database\OperationsController::class => [
'class' => PhpMyAdmin\Controllers\Database\OperationsController::class,
'arguments' => [
@@ -230,6 +240,168 @@ return [
'$db' => '%db%',
],
],
+ PhpMyAdmin\Controllers\Database\Structure\AddPrefixController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\AddPrefixController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\AddPrefixTableController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\AddPrefixTableController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CentralColumns\AddController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CentralColumns\AddController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CentralColumns\MakeConsistentController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CentralColumns\MakeConsistentController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CentralColumns\RemoveController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CentralColumns\RemoveController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\ChangePrefixFormController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\ChangePrefixFormController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CopyFormController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CopyFormController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CopyTableController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CopyTableController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$operations' => '@operations',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\CopyTableWithPrefixController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\CopyTableWithPrefixController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\DropFormController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\DropFormController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\DropTableController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\DropTableController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$relationCleanup' => '@relation_cleanup',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\EmptyFormController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\EmptyFormController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\EmptyTableController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\EmptyTableController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$relation' => '@relation',
+ '$relationCleanup' => '@relation_cleanup',
+ '$operations' => '@operations',
+ '$flash' => '@flash',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$relation' => '@relation',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\RealRowCountController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\RealRowCountController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\ReplacePrefixController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\ReplacePrefixController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ '$structureController' => '@' . PhpMyAdmin\Controllers\Database\StructureController::class,
+ ],
+ ],
+ PhpMyAdmin\Controllers\Database\Structure\ShowCreateController::class => [
+ 'class' => PhpMyAdmin\Controllers\Database\Structure\ShowCreateController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$db' => '%db%',
+ '$dbi' => '@dbi',
+ ],
+ ],
PhpMyAdmin\Controllers\Database\StructureController::class => [
'class' => PhpMyAdmin\Controllers\Database\StructureController::class,
'arguments' => [
@@ -279,6 +451,13 @@ return [
'$errorHandler' => '@error_handler',
],
],
+ PhpMyAdmin\Controllers\Export\CheckTimeOutController::class => [
+ 'class' => PhpMyAdmin\Controllers\Export\CheckTimeOutController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ ],
+ ],
PhpMyAdmin\Controllers\Export\ExportController::class => [
'class' => PhpMyAdmin\Controllers\Export\ExportController::class,
'arguments' => [
@@ -523,6 +702,24 @@ return [
'$dbi' => '@dbi',
],
],
+ PhpMyAdmin\Controllers\Server\Databases\CreateController::class => [
+ 'class' => PhpMyAdmin\Controllers\Server\Databases\CreateController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$dbi' => '@dbi',
+ ],
+ ],
+ PhpMyAdmin\Controllers\Server\Databases\DestroyController::class => [
+ 'class' => PhpMyAdmin\Controllers\Server\Databases\DestroyController::class,
+ 'arguments' => [
+ '$response' => '@response',
+ '$template' => '@template',
+ '$dbi' => '@dbi',
+ '$transformations' => '@transformations',
+ '$relationCleanup' => '@relation_cleanup',
+ ],
+ ],
PhpMyAdmin\Controllers\Server\DatabasesController::class => [
'class' => PhpMyAdmin\Controllers\Server\DatabasesController::class,
'arguments' => [
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 16b4ff82ae..63360a3ad1 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1352,12 +1352,38 @@
<code>$table</code>
</MixedAssignment>
</file>
- <file src="libraries/classes/Controllers/Database/OperationsController.php">
- <MixedArgument occurrences="17">
- <code>$_POST['comment']</code>
+ <file src="libraries/classes/Controllers/Database/Operations/CollationController.php">
+ <MixedArgument occurrences="7">
<code>$_POST['db_collation']</code>
<code>$_POST['db_collation'] ?? ''</code>
<code>$_POST['db_collation'] ?? ''</code>
+ <code>$db</code>
+ <code>$db</code>
+ <code>$db</code>
+ <code>$tableName</code>
+ </MixedArgument>
+ <MixedArgumentTypeCoercion occurrences="1">
+ <code>['db' =&gt; $db]</code>
+ </MixedArgumentTypeCoercion>
+ <MixedAssignment occurrences="2">
+ <code>$data</code>
+ <code>$tableName</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="3">
+ <code>Util::backquote($db)</code>
+ <code>Util::backquote($db)</code>
+ <code>Util::backquote($tableName)</code>
+ </MixedOperand>
+ <PossiblyNullArgument occurrences="1">
+ <code>$_POST['db_collation']</code>
+ </PossiblyNullArgument>
+ <UnusedForeachValue occurrences="1">
+ <code>$data</code>
+ </UnusedForeachValue>
+ </file>
+ <file src="libraries/classes/Controllers/Database/OperationsController.php">
+ <MixedArgument occurrences="10">
+ <code>$_POST['comment']</code>
<code>$_POST['newname']</code>
<code>$_POST['newname']</code>
<code>$_POST['newname']</code>
@@ -1366,14 +1392,9 @@
<code>$db</code>
<code>$db</code>
<code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
<code>$message</code>
- <code>$tableName</code>
</MixedArgument>
- <MixedArgumentTypeCoercion occurrences="2">
- <code>['db' =&gt; $db]</code>
+ <MixedArgumentTypeCoercion occurrences="1">
<code>['db' =&gt; $db]</code>
</MixedArgumentTypeCoercion>
<MixedArrayAssignment occurrences="1">
@@ -1382,21 +1403,13 @@
<MixedArrayOffset occurrences="1">
<code>$cfg['Servers'][$server]</code>
</MixedArrayOffset>
- <MixedAssignment occurrences="4">
- <code>$data</code>
+ <MixedAssignment occurrences="2">
<code>$db</code>
<code>$db</code>
- <code>$tableName</code>
</MixedAssignment>
- <MixedOperand occurrences="4">
- <code>Util::backquote($db)</code>
- <code>Util::backquote($db)</code>
+ <MixedOperand occurrences="1">
<code>Util::backquote($db)</code>
- <code>Util::backquote($tableName)</code>
</MixedOperand>
- <PossiblyNullArgument occurrences="1">
- <code>$_POST['db_collation']</code>
- </PossiblyNullArgument>
<RedundantCondition occurrences="5">
<code>! $_error</code>
<code>! $_error</code>
@@ -1407,9 +1420,6 @@
<TypeDoesNotContainNull occurrences="1">
<code>''</code>
</TypeDoesNotContainNull>
- <UnusedForeachValue occurrences="1">
- <code>$data</code>
- </UnusedForeachValue>
</file>
<file src="libraries/classes/Controllers/Database/PrivilegesController.php">
<MixedArgument occurrences="1">
@@ -1505,28 +1515,295 @@
<code>$query</code>
</PossiblyNullArgument>
</file>
- <file src="libraries/classes/Controllers/Database/StructureController.php">
- <InvalidScalarArgument occurrences="2">
- <code>$formattedOverhead</code>
- <code>$formattedSize</code>
- </InvalidScalarArgument>
- <MixedArgument occurrences="89">
+ <file src="libraries/classes/Controllers/Database/Structure/AddPrefixController.php">
+ <MixedAssignment occurrences="3">
+ <code>$params['selected'][]</code>
+ <code>$selected</code>
+ <code>$selectedValue</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/AddPrefixTableController.php">
+ <MixedArgument occurrences="3">
+ <code>$db</code>
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="3">
+ <code>$_POST['add_prefix']</code>
+ <code>Util::backquote($newTableName)</code>
+ <code>Util::backquote($selected[$i])</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CentralColumns/AddController.php">
+ <MixedArgument occurrences="1">
+ <code>$selected</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CentralColumns/MakeConsistentController.php">
+ <MixedArgument occurrences="2">
+ <code>$db</code>
+ <code>$selected</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CentralColumns/RemoveController.php">
+ <MixedArgument occurrences="2">
<code>$_POST['db']</code>
- <code>$_POST['master_connection'] ?? null</code>
+ <code>$selected</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/ChangePrefixFormController.php">
+ <MixedAssignment occurrences="4">
+ <code>$selected</code>
+ <code>$selectedValue</code>
+ <code>$submitMult</code>
+ <code>$urlParams['selected'][]</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CopyFormController.php">
+ <MixedAssignment occurrences="6">
+ <code>$databaseName</code>
+ <code>$databasesList</code>
+ <code>$key</code>
+ <code>$selected</code>
+ <code>$selectedValue</code>
+ <code>$urlParams['selected'][]</code>
+ </MixedAssignment>
+ <MixedMethodCall occurrences="2">
+ <code>getList</code>
+ <code>offsetUnset</code>
+ </MixedMethodCall>
+ <MixedPropertyFetch occurrences="1">
+ <code>$dblist-&gt;databases</code>
+ </MixedPropertyFetch>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CopyTableController.php">
+ <MixedArgument occurrences="9">
<code>$_POST['what']</code>
- <code>$_REQUEST['pos']</code>
- <code>$checkTime</code>
- <code>$checkTimeAll</code>
- <code>$createTime</code>
- <code>$createTimeAll</code>
+ <code>$db</code>
+ <code>$db</code>
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ <code>$targetDb</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="2">
+ <code>$selected</code>
+ <code>$targetDb</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/CopyTableWithPrefixController.php">
+ <MixedArgument occurrences="5">
+ <code>$current</code>
+ <code>$current</code>
+ <code>$db</code>
+ <code>$db</code>
+ <code>$selected</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="4">
<code>$current</code>
+ <code>$fromPrefix</code>
+ <code>$selected</code>
+ <code>$toPrefix</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="1">
+ <code>$toPrefix</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/DropFormController.php">
+ <MixedArgument occurrences="3">
<code>$current</code>
<code>$current</code>
+ <code>$db</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="7">
<code>$current</code>
<code>$current</code>
+ <code>$selected</code>
+ <code>$selectedValue</code>
+ <code>$selectedValue</code>
+ <code>$urlParams['selected'][]</code>
+ <code>$urlParams['views'][]</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="2">
+ <code>Util::backquote(htmlspecialchars($current))</code>
+ <code>Util::backquote(htmlspecialchars($current))</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/DropTableController.php">
+ <MixedArgument occurrences="5">
+ <code>$current</code>
+ <code>$current</code>
+ <code>$db</code>
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="3">
+ <code>$_SESSION['tmpval']['table_limit_offset']</code>
+ <code>$_SESSION['tmpval']['table_limit_offset_db']</code>
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="6">
+ <code>$current</code>
+ <code>$multBtn</code>
+ <code>$reload</code>
+ <code>$result</code>
+ <code>$result</code>
+ <code>$selected</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="2">
+ <code>Util::backquote($current)</code>
+ <code>Util::backquote($current)</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/EmptyFormController.php">
+ <MixedArgument occurrences="1">
+ <code>$selectedValue</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="2">
+ <code>$selected</code>
+ <code>$selectedValue</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="1">
+ <code>Util::backquote(htmlspecialchars($selectedValue))</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/EmptyTableController.php">
+ <MixedArgument occurrences="6">
+ <code>$_REQUEST['pos']</code>
+ <code>$db</code>
+ <code>$db</code>
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ <code>$table</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="2">
+ <code>$multBtn</code>
+ <code>$selected</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="1">
+ <code>Util::backquote($selected[$i])</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/FavoriteTableController.php">
+ <MixedArgument occurrences="5">
+ <code>$favoriteTable</code>
+ <code>$favoriteTables</code>
+ <code>$parameters['favoriteTables']</code>
+ <code>$value['db']</code>
+ <code>$value['table']</code>
+ </MixedArgument>
+ <MixedArgumentTypeCoercion occurrences="1">
+ <code>['db' =&gt; $db]</code>
+ </MixedArgumentTypeCoercion>
+ <MixedArrayAccess occurrences="5">
+ <code>$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]</code>
+ <code>$value['db']</code>
+ <code>$value['db']</code>
+ <code>$value['table']</code>
+ <code>$value['table']</code>
+ </MixedArrayAccess>
+ <MixedArrayAssignment occurrences="2">
+ <code>$_SESSION['tmpval']['favorites_synced']</code>
+ <code>$favoriteTables[$user]</code>
+ </MixedArrayAssignment>
+ <MixedAssignment occurrences="6">
+ <code>$favoriteTable</code>
+ <code>$favoriteTables</code>
+ <code>$favoriteTables</code>
+ <code>$key</code>
+ <code>$value</code>
+ <code>$value</code>
+ </MixedAssignment>
+ <UnusedVariable occurrences="1">
+ <code>$key</code>
+ </UnusedVariable>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/RealRowCountController.php">
+ <MixedArgument occurrences="1">
+ <code>$table['TABLE_NAME']</code>
+ </MixedArgument>
+ <MixedArgumentTypeCoercion occurrences="1">
+ <code>['db' =&gt; $db]</code>
+ </MixedArgumentTypeCoercion>
+ <MixedArrayAccess occurrences="2">
+ <code>$table['TABLE_NAME']</code>
+ <code>$table['TABLE_NAME']</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="1">
+ <code>$table</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/ReplacePrefixController.php">
+ <MixedArgument occurrences="6">
<code>$current</code>
<code>$current</code>
+ <code>$db</code>
+ <code>$newTableName</code>
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="5">
<code>$current</code>
+ <code>$fromPrefix</code>
+ <code>$newTableName</code>
+ <code>$selected</code>
+ <code>$toPrefix</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="3">
+ <code>$toPrefix</code>
+ <code>Util::backquote($newTableName)</code>
+ <code>Util::backquote($selected[$i])</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Database/Structure/ShowCreateController.php">
+ <MixedArgument occurrences="2">
+ <code>$object-&gt;showCreate()</code>
+ <code>$selected</code>
+ </MixedArgument>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ </file>
+ <file src="libraries/classes/Controllers/Database/StructureController.php">
+ <InvalidScalarArgument occurrences="2">
+ <code>$formattedOverhead</code>
+ <code>$formattedSize</code>
+ </InvalidScalarArgument>
+ <MixedArgument occurrences="38">
+ <code>$_POST['master_connection'] ?? null</code>
+ <code>$checkTime</code>
+ <code>$checkTimeAll</code>
+ <code>$createTime</code>
+ <code>$createTimeAll</code>
<code>$currentTable</code>
<code>$currentTable</code>
<code>$currentTable['Collation']</code>
@@ -1543,25 +1820,9 @@
<code>$currentTable['TABLE_NAME']</code>
<code>$currentTable['TABLE_NAME']</code>
<code>$currentTable['TABLE_NAME']</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
- <code>$db</code>
<code>$dbTable</code>
<code>$dbTable</code>
- <code>$favoriteTable</code>
- <code>$favoriteTables</code>
- <code>$newTableName</code>
- <code>$object-&gt;showCreate()</code>
<code>$overheadSize</code>
- <code>$parameters['favoriteTables']</code>
<code>$replicaInfo['Do_DB']</code>
<code>$replicaInfo['Do_DB']</code>
<code>$replicaInfo['Do_DB']</code>
@@ -1570,45 +1831,17 @@
<code>$replicaInfo['Ignore_Table']</code>
<code>$replicaInfo['Wild_Do_Table']</code>
<code>$replicaInfo['Wild_Ignore_Table']</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selectedValue</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
<code>$sumSize</code>
- <code>$table</code>
<code>$tableIsView</code>
- <code>$table['TABLE_NAME']</code>
- <code>$targetDb</code>
<code>$truename</code>
<code>$updateTime</code>
<code>$updateTimeAll</code>
- <code>$value['db']</code>
- <code>$value['table']</code>
</MixedArgument>
- <MixedArgumentTypeCoercion occurrences="3">
- <code>['db' =&gt; $db]</code>
- <code>['db' =&gt; $db]</code>
+ <MixedArgumentTypeCoercion occurrences="1">
<code>['db' =&gt; $db]</code>
</MixedArgumentTypeCoercion>
- <MixedArrayAccess occurrences="31">
+ <MixedArrayAccess occurrences="19">
<code>$_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']]</code>
- <code>$_SESSION['tmpval']['table_limit_offset']</code>
- <code>$_SESSION['tmpval']['table_limit_offset_db']</code>
<code>$currentTable['Check_time']</code>
<code>$currentTable['Collation']</code>
<code>$currentTable['Create_time']</code>
@@ -1625,135 +1858,54 @@
<code>$currentTable['TABLE_ROWS']</code>
<code>$currentTable['TABLE_TYPE']</code>
<code>$currentTable['Update_time']</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$table['TABLE_NAME']</code>
- <code>$table['TABLE_NAME']</code>
<code>$value['db']</code>
- <code>$value['db']</code>
- <code>$value['table']</code>
<code>$value['table']</code>
</MixedArrayAccess>
- <MixedArrayAssignment occurrences="3">
- <code>$_SESSION['tmpval']['favorites_synced']</code>
+ <MixedArrayAssignment occurrences="1">
<code>$currentTable['TABLE_ROWS']</code>
- <code>$favoriteTables[$user]</code>
</MixedArrayAssignment>
- <MixedAssignment occurrences="80">
+ <MixedAssignment occurrences="29">
<code>$charset</code>
<code>$checkTime</code>
<code>$checkTimeAll</code>
<code>$createTime</code>
<code>$createTimeAll</code>
- <code>$current</code>
- <code>$current</code>
- <code>$current</code>
- <code>$current</code>
- <code>$current</code>
<code>$currentTable</code>
<code>$currentTable['Rows']</code>
<code>$currentTable['TABLE_ROWS']</code>
<code>$currentTable['TABLE_ROWS']</code>
- <code>$databaseName</code>
- <code>$databasesList</code>
<code>$dbTable</code>
- <code>$favoriteTable</code>
- <code>$favoriteTables</code>
<code>$favoriteTables</code>
- <code>$fromPrefix</code>
- <code>$fromPrefix</code>
- <code>$key</code>
- <code>$key</code>
- <code>$multBtn</code>
- <code>$multBtn</code>
- <code>$newTableName</code>
<code>$overheadSize</code>
- <code>$params['selected'][]</code>
- <code>$reload</code>
- <code>$result</code>
- <code>$result</code>
<code>$searchDb</code>
<code>$searchDoDBInDB</code>
<code>$searchDoDBInTruename</code>
<code>$searchTable</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selected</code>
- <code>$selectedValue</code>
- <code>$selectedValue</code>
- <code>$selectedValue</code>
- <code>$selectedValue</code>
- <code>$selectedValue</code>
- <code>$selectedValue</code>
- <code>$submitMult</code>
<code>$sumEntries</code>
- <code>$table</code>
- <code>$targetDb</code>
<code>$this-&gt;dbIsSystemSchema</code>
<code>$this-&gt;isShowStats</code>
<code>$this-&gt;numTables</code>
<code>$this-&gt;position</code>
<code>$this-&gt;tables</code>
<code>$this-&gt;totalNumTables</code>
- <code>$toPrefix</code>
- <code>$toPrefix</code>
<code>$truename</code>
<code>$updateTime</code>
<code>$updateTimeAll</code>
- <code>$urlParams['selected'][]</code>
- <code>$urlParams['selected'][]</code>
- <code>$urlParams['selected'][]</code>
<code>$urlParams['sort']</code>
<code>$urlParams['sort_order']</code>
- <code>$urlParams['views'][]</code>
- <code>$value</code>
<code>$value</code>
</MixedAssignment>
- <MixedMethodCall occurrences="3">
+ <MixedMethodCall occurrences="1">
<code>getCharset</code>
- <code>getList</code>
- <code>offsetUnset</code>
</MixedMethodCall>
- <MixedOperand occurrences="20">
- <code>$_POST['add_prefix']</code>
+ <MixedOperand occurrences="7">
<code>$currentTable['Data_free']</code>
<code>$currentTable['Data_length']</code>
<code>$currentTable['Data_length']</code>
<code>$currentTable['Data_length']</code>
<code>$currentTable['TABLE_NAME']</code>
<code>$currentTable['TABLE_ROWS']</code>
- <code>$toPrefix</code>
- <code>$toPrefix</code>
- <code>Util::backquote($current)</code>
- <code>Util::backquote($current)</code>
- <code>Util::backquote($newTableName)</code>
- <code>Util::backquote($newTableName)</code>
- <code>Util::backquote($selected[$i])</code>
- <code>Util::backquote($selected[$i])</code>
- <code>Util::backquote($selected[$i])</code>
- <code>Util::backquote(htmlspecialchars($current))</code>
- <code>Util::backquote(htmlspecialchars($current))</code>
- <code>Util::backquote(htmlspecialchars($selectedValue))</code>
</MixedOperand>
- <MixedPropertyFetch occurrences="1">
- <code>$dblist-&gt;databases</code>
- </MixedPropertyFetch>
<PossiblyNullArrayAccess occurrences="8">
<code>$formattedOverhead</code>
<code>$formattedSize</code>
@@ -1772,8 +1924,7 @@
<code>$tables</code>
<code>$totalNumTables</code>
</PropertyNotSetInConstructor>
- <UnusedVariable occurrences="2">
- <code>$key</code>
+ <UnusedVariable occurrences="1">
<code>$keyname</code>
</UnusedVariable>
</file>
@@ -2369,19 +2520,62 @@
<code>$this-&gt;collations[$charset-&gt;getName()]</code>
</PossiblyNullIterator>
</file>
- <file src="libraries/classes/Controllers/Server/DatabasesController.php">
- <MixedArgument occurrences="23">
- <code>$_POST['master_connection'] ?? null</code>
+ <file src="libraries/classes/Controllers/Server/Databases/CreateController.php">
+ <MixedArgument occurrences="7">
<code>$collations[$databaseCharset]</code>
- <code>$database['DEFAULT_COLLATION_NAME']</code>
- <code>$database['SCHEMA_NAME']</code>
- <code>$dblist-&gt;databases</code>
<code>$params['db_collation']</code>
<code>$params['db_collation']</code>
<code>$params['db_collation']</code>
<code>$params['new_db']</code>
<code>$params['new_db']</code>
<code>$params['new_db']</code>
+ </MixedArgument>
+ <MixedArgumentTypeCoercion occurrences="1">
+ <code>['db' =&gt; $params['new_db']]</code>
+ </MixedArgumentTypeCoercion>
+ <MixedAssignment occurrences="2">
+ <code>$db</code>
+ <code>$result</code>
+ </MixedAssignment>
+ <MixedOperand occurrences="1">
+ <code>Util::backquote($params['new_db'])</code>
+ </MixedOperand>
+ </file>
+ <file src="libraries/classes/Controllers/Server/Databases/DestroyController.php">
+ <MixedArgument occurrences="4">
+ <code>$selected</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="3">
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ <code>$selected[$i]</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="1">
+ <code>$selected</code>
+ </MixedAssignment>
+ <MixedMethodCall occurrences="1">
+ <code>build</code>
+ </MixedMethodCall>
+ <MixedOperand occurrences="1">
+ <code>Util::backquote($selected[$i])</code>
+ </MixedOperand>
+ <MixedPropertyFetch occurrences="1">
+ <code>$dblist-&gt;databases</code>
+ </MixedPropertyFetch>
+ <UnusedVariable occurrences="2">
+ <code>$sqlQuery</code>
+ <code>$sqlQuery</code>
+ </UnusedVariable>
+ </file>
+ <file src="libraries/classes/Controllers/Server/DatabasesController.php">
+ <MixedArgument occurrences="12">
+ <code>$_POST['master_connection'] ?? null</code>
+ <code>$database['DEFAULT_COLLATION_NAME']</code>
+ <code>$database['SCHEMA_NAME']</code>
+ <code>$dblist-&gt;databases</code>
<code>$params['sort_by']</code>
<code>$params['sort_order']</code>
<code>$primaryInfo['Do_DB']</code>
@@ -2390,16 +2584,11 @@
<code>$replicaInfo['Do_DB']</code>
<code>$replicaInfo['Do_DB']</code>
<code>$replicaInfo['Ignore_DB']</code>
- <code>$selected</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
</MixedArgument>
- <MixedArgumentTypeCoercion occurrences="2">
+ <MixedArgumentTypeCoercion occurrences="1">
<code>['db' =&gt; $database['SCHEMA_NAME']]</code>
- <code>['db' =&gt; $params['new_db']]</code>
</MixedArgumentTypeCoercion>
- <MixedArrayAccess occurrences="16">
+ <MixedArrayAccess occurrences="13">
<code>$database[$key]</code>
<code>$database['DEFAULT_COLLATION_NAME']</code>
<code>$database['SCHEMA_NAME']</code>
@@ -2412,9 +2601,6 @@
<code>$database['SCHEMA_NAME']</code>
<code>$database['SCHEMA_NAME']</code>
<code>$database['SCHEMA_NAME']</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
- <code>$selected[$i]</code>
<code>$totalStatistics[$key]['raw']</code>
</MixedArrayAccess>
<MixedArrayAssignment occurrences="2">
@@ -2425,28 +2611,19 @@
<code>$databases[$database['SCHEMA_NAME']]</code>
<code>$databases[$database['SCHEMA_NAME']]</code>
</MixedArrayOffset>
- <MixedAssignment occurrences="10">
+ <MixedAssignment occurrences="7">
<code>$database</code>
- <code>$db</code>
<code>$key</code>
<code>$key</code>
<code>$key</code>
<code>$key</code>
- <code>$result</code>
- <code>$selected</code>
<code>$statistics[$key]['raw']</code>
<code>$totalStatistics[$key]['raw']</code>
</MixedAssignment>
- <MixedMethodCall occurrences="1">
- <code>build</code>
- </MixedMethodCall>
- <MixedOperand occurrences="3">
+ <MixedOperand occurrences="1">
<code>$totalStatistics[$key]['raw']</code>
- <code>Util::backquote($params['new_db'])</code>
- <code>Util::backquote($selected[$i])</code>
</MixedOperand>
- <MixedPropertyFetch occurrences="2">
- <code>$dblist-&gt;databases</code>
+ <MixedPropertyFetch occurrences="1">
<code>$dblist-&gt;databases</code>
</MixedPropertyFetch>
<PropertyNotSetInConstructor occurrences="4">
@@ -2461,10 +2638,6 @@
<TypeDoesNotContainNull occurrences="1">
<code>0</code>
</TypeDoesNotContainNull>
- <UnusedVariable occurrences="2">
- <code>$sqlQuery</code>
- <code>$sqlQuery</code>
- </UnusedVariable>
</file>
<file src="libraries/classes/Controllers/Server/EnginesController.php">
<MixedArgument occurrences="3">
@@ -17206,14 +17379,24 @@
<code>include $this-&gt;object-&gt;defaultSource</code>
</UnresolvableInclude>
</file>
+ <file src="test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php">
+ <MixedArgument occurrences="1">
+ <code>$json</code>
+ </MixedArgument>
+ <MixedArrayAccess occurrences="1">
+ <code>$json['favoriteTables']</code>
+ </MixedArrayAccess>
+ <MixedAssignment occurrences="1">
+ <code>$json</code>
+ </MixedAssignment>
+ </file>
<file src="test/classes/Controllers/Database/StructureControllerTest.php">
- <MixedArgument occurrences="4">
+ <MixedArgument occurrences="3">
<code>$currentTable</code>
- <code>$json</code>
<code>$result</code>
<code>$result</code>
</MixedArgument>
- <MixedArrayAccess occurrences="24">
+ <MixedArrayAccess occurrences="23">
<code>$currentTable</code>
<code>$currentTable</code>
<code>$currentTable</code>
@@ -17229,7 +17412,6 @@
<code>$currentTable['Data_free']</code>
<code>$currentTable['Rows']</code>
<code>$currentTable['TABLE_ROWS']</code>
- <code>$json['favoriteTables']</code>
<code>$overheadSize</code>
<code>$overheadSize</code>
<code>$sumSize</code>
@@ -17245,8 +17427,7 @@
<code>$currentTable['ENGINE']</code>
<code>$currentTable['ENGINE']</code>
</MixedArrayAssignment>
- <MixedAssignment occurrences="11">
- <code>$json</code>
+ <MixedAssignment occurrences="10">
<code>$result</code>
<code>$result</code>
<code>[$currentTable, , , $sumSize]</code>
@@ -17279,11 +17460,15 @@
<code>$responseMessage</code>
</MixedAssignment>
</file>
- <file src="test/classes/Controllers/Server/DatabasesControllerTest.php">
- <MixedArgument occurrences="5">
+ <file src="test/classes/Controllers/Server/Databases/CreateControllerTest.php">
+ <MixedArgument occurrences="3">
<code>$actual['message']</code>
<code>$actual['message']</code>
<code>$actual['message']</code>
+ </MixedArgument>
+ </file>
+ <file src="test/classes/Controllers/Server/Databases/DestroyControllerTest.php">
+ <MixedArgument occurrences="2">
<code>$actual['message']</code>
<code>$actual['message']</code>
</MixedArgument>
diff --git a/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php b/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php
new file mode 100644
index 0000000000..31eb2229f4
--- /dev/null
+++ b/test/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php
@@ -0,0 +1,63 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Tests\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController;
+use PhpMyAdmin\RecentFavoriteTable;
+use PhpMyAdmin\Relation;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Tests\AbstractTestCase;
+use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub;
+use ReflectionClass;
+
+use function json_encode;
+
+/**
+ * @covers \PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController
+ */
+class FavoriteTableControllerTest extends AbstractTestCase
+{
+ public function testSynchronizeFavoriteTables(): void
+ {
+ $GLOBALS['server'] = 1;
+ $GLOBALS['text_dir'] = 'ltr';
+ $GLOBALS['PMA_PHP_SELF'] = 'index.php';
+
+ $favoriteInstance = $this->getMockBuilder(RecentFavoriteTable::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $favoriteInstance->expects($this->exactly(2))
+ ->method('getTables')
+ ->will($this->onConsecutiveCalls([[]], [['db' => 'db', 'table' => 'table']]));
+
+ $class = new ReflectionClass(FavoriteTableController::class);
+ $method = $class->getMethod('synchronizeFavoriteTables');
+ $method->setAccessible(true);
+ $template = new Template();
+
+ $controller = new FavoriteTableController(
+ new ResponseStub(),
+ $template,
+ 'db',
+ new Relation($this->dbi, $template)
+ );
+
+ // The user hash for test
+ $user = 'abcdefg';
+ $favoriteTable = [
+ $user => [
+ [
+ 'db' => 'db',
+ 'table' => 'table',
+ ],
+ ],
+ ];
+
+ $json = $method->invokeArgs($controller, [$favoriteInstance, $user, $favoriteTable]);
+
+ $this->assertEquals(json_encode($favoriteTable), $json['favoriteTables'] ?? '');
+ $this->assertArrayHasKey('list', $json);
+ }
+}
diff --git a/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php b/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php
new file mode 100644
index 0000000000..07ddd9ad8d
--- /dev/null
+++ b/test/classes/Controllers/Database/Structure/RealRowCountControllerTest.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Tests\Controllers\Database\Structure;
+
+use PhpMyAdmin\Controllers\Database\Structure\RealRowCountController;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Tests\AbstractTestCase;
+use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub;
+
+use function json_encode;
+
+/**
+ * @covers \PhpMyAdmin\Controllers\Database\Structure\RealRowCountController
+ */
+class RealRowCountControllerTest extends AbstractTestCase
+{
+ public function testRealRowCount(): void
+ {
+ $GLOBALS['server'] = 1;
+ $GLOBALS['text_dir'] = 'ltr';
+ $GLOBALS['PMA_PHP_SELF'] = 'index.php';
+ $GLOBALS['cfg']['Server']['DisableIS'] = true;
+ $GLOBALS['is_db'] = true;
+ $GLOBALS['db'] = 'world';
+
+ $response = new ResponseStub();
+ $response->setAjax(true);
+
+ $_REQUEST['table'] = 'City';
+
+ (new RealRowCountController($response, new Template(), 'world', $this->dbi))();
+
+ $json = $response->getJSONResult();
+ $this->assertEquals('4,079', $json['real_row_count']);
+
+ $_REQUEST['real_row_count_all'] = 'on';
+
+ (new RealRowCountController($response, new Template(), 'world', $this->dbi))();
+
+ $json = $response->getJSONResult();
+ $expected = [
+ ['table' => 'City', 'row_count' => 4079],
+ ['table' => 'Country', 'row_count' => 239],
+ ['table' => 'CountryLanguage', 'row_count' => 984],
+ ];
+ $this->assertEquals(json_encode($expected), $json['real_row_count_all']);
+ }
+}
diff --git a/test/classes/Controllers/Database/StructureControllerTest.php b/test/classes/Controllers/Database/StructureControllerTest.php
index 576a1e7804..5aa1a450a5 100644
--- a/test/classes/Controllers/Database/StructureControllerTest.php
+++ b/test/classes/Controllers/Database/StructureControllerTest.php
@@ -8,7 +8,6 @@ use PhpMyAdmin\Controllers\Database\StructureController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\FlashMessages;
use PhpMyAdmin\Operations;
-use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Relation;
use PhpMyAdmin\RelationCleanup;
use PhpMyAdmin\Replication;
@@ -16,12 +15,9 @@ use PhpMyAdmin\Table;
use PhpMyAdmin\Template;
use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub;
-use PHPUnit\Framework\MockObject\MockObject;
use ReflectionClass;
use ReflectionException;
-use function json_encode;
-
/**
* @covers \PhpMyAdmin\Controllers\Database\StructureController
*/
@@ -393,113 +389,6 @@ class StructureControllerTest extends AbstractTestCase
}
/**
- * Tests for synchronizeFavoriteTables()
- */
- public function testSynchronizeFavoriteTables(): void
- {
- $favoriteInstance = $this->getFavoriteTablesMock();
-
- $class = new ReflectionClass(StructureController::class);
- $method = $class->getMethod('synchronizeFavoriteTables');
- $method->setAccessible(true);
-
- $controller = new StructureController(
- $this->response,
- $this->template,
- $GLOBALS['db'],
- $this->relation,
- $this->replication,
- $this->relationCleanup,
- $this->operations,
- $GLOBALS['dbi'],
- $this->flash
- );
-
- // The user hash for test
- $user = 'abcdefg';
- $favoriteTable = [
- $user => [
- [
- 'db' => 'db',
- 'table' => 'table',
- ],
- ],
- ];
-
- $json = $method->invokeArgs($controller, [$favoriteInstance, $user, $favoriteTable]);
-
- $this->assertEquals(json_encode($favoriteTable), $json['favoriteTables'] ?? '');
- $this->assertArrayHasKey('list', $json);
- }
-
- /**
- * @return MockObject|RecentFavoriteTable
- */
- private function getFavoriteTablesMock()
- {
- $favoriteInstance = $this->getMockBuilder(RecentFavoriteTable::class)
- ->disableOriginalConstructor()
- ->getMock();
- $favoriteInstance->expects($this->exactly(2))
- ->method('getTables')
- ->will($this->onConsecutiveCalls([[]], [['db' => 'db', 'table' => 'table']]));
-
- return $favoriteInstance;
- }
-
- /**
- * Tests for handleRealRowCountRequestAction()
- */
- public function testHandleRealRowCountRequestAction(): void
- {
- global $is_db;
-
- $is_db = true;
-
- $this->response->setAjax(true);
- $controller = new StructureController(
- $this->response,
- $this->template,
- $GLOBALS['db'],
- $this->relation,
- $this->replication,
- $this->relationCleanup,
- $this->operations,
- $GLOBALS['dbi'],
- $this->flash
- );
- // Showing statistics
- $class = new ReflectionClass(StructureController::class);
- $property = $class->getProperty('tables');
- $property->setAccessible(true);
-
- $_REQUEST['table'] = 'table';
- $controller->handleRealRowCountRequestAction();
- $json = $this->response->getJSONResult();
- $this->assertEquals(
- 6,
- $json['real_row_count']
- );
-
- // Fall into another branch
- $property->setValue($controller, [['TABLE_NAME' => 'table']]);
- $_REQUEST['real_row_count_all'] = 'abc';
- $controller->handleRealRowCountRequestAction();
- $json = $this->response->getJSONResult();
-
- $expectedResult = [
- [
- 'table' => 'table',
- 'row_count' => 6,
- ],
- ];
- $this->assertEquals(
- json_encode($expectedResult),
- $json['real_row_count_all']
- );
- }
-
- /**
* @throws ReflectionException
*/
public function testDisplayTableList(): void
diff --git a/test/classes/Controllers/Server/Databases/CreateControllerTest.php b/test/classes/Controllers/Server/Databases/CreateControllerTest.php
new file mode 100644
index 0000000000..53116cfa6a
--- /dev/null
+++ b/test/classes/Controllers/Server/Databases/CreateControllerTest.php
@@ -0,0 +1,61 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Tests\Controllers\Server\Databases;
+
+use PhpMyAdmin\Controllers\Server\Databases\CreateController;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Tests\AbstractTestCase;
+use PhpMyAdmin\Tests\Stubs\ResponseRenderer;
+
+use function __;
+use function sprintf;
+
+/**
+ * @covers \PhpMyAdmin\Controllers\Server\Databases\CreateController
+ */
+final class CreateControllerTest extends AbstractTestCase
+{
+ public function testCreateDatabase(): void
+ {
+ $GLOBALS['server'] = 1;
+ $GLOBALS['text_dir'] = 'ltr';
+ $GLOBALS['PMA_PHP_SELF'] = 'index.php';
+ $GLOBALS['cfg']['Server']['DisableIS'] = false;
+ $GLOBALS['db'] = 'pma_test';
+ $GLOBALS['table'] = '';
+
+ $response = new ResponseRenderer();
+ $response->setAjax(true);
+
+ $template = new Template();
+ $controller = new CreateController($response, $template, $this->dbi);
+
+ $_POST['new_db'] = 'test_db_error';
+
+ $controller();
+ $actual = $response->getJSONResult();
+
+ $this->assertArrayHasKey('message', $actual);
+ $this->assertStringContainsString('<div class="alert alert-danger" role="alert">', $actual['message']);
+
+ $response = new ResponseRenderer();
+ $response->setAjax(true);
+
+ $controller = new CreateController($response, $template, $this->dbi);
+
+ $_POST['new_db'] = 'test_db';
+ $_POST['db_collation'] = 'utf8_general_ci';
+
+ $controller();
+ $actual = $response->getJSONResult();
+
+ $this->assertArrayHasKey('message', $actual);
+ $this->assertStringContainsString('<div class="alert alert-success" role="alert">', $actual['message']);
+ $this->assertStringContainsString(
+ sprintf(__('Database %1$s has been created.'), 'test_db'),
+ $actual['message']
+ );
+ }
+}
diff --git a/test/classes/Controllers/Server/Databases/DestroyControllerTest.php b/test/classes/Controllers/Server/Databases/DestroyControllerTest.php
new file mode 100644
index 0000000000..377d84dc24
--- /dev/null
+++ b/test/classes/Controllers/Server/Databases/DestroyControllerTest.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Tests\Controllers\Server\Databases;
+
+use PhpMyAdmin\Controllers\Server\Databases\DestroyController;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Relation;
+use PhpMyAdmin\RelationCleanup;
+use PhpMyAdmin\Template;
+use PhpMyAdmin\Tests\AbstractTestCase;
+use PhpMyAdmin\Tests\Stubs\ResponseRenderer;
+use PhpMyAdmin\Transformations;
+
+use function __;
+
+/**
+ * @covers \PhpMyAdmin\Controllers\Server\Databases\DestroyController
+ */
+class DestroyControllerTest extends AbstractTestCase
+{
+ public function testDropDatabases(): void
+ {
+ global $cfg;
+
+ $GLOBALS['server'] = 1;
+ $GLOBALS['text_dir'] = 'ltr';
+ $GLOBALS['PMA_PHP_SELF'] = 'index.php';
+
+ $dbi = $this->getMockBuilder(DatabaseInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $response = new ResponseRenderer();
+ $response->setAjax(true);
+
+ $cfg['AllowUserDropDatabase'] = true;
+
+ $template = new Template();
+ $controller = new DestroyController(
+ $response,
+ $template,
+ $dbi,
+ new Transformations(),
+ new RelationCleanup($dbi, new Relation($dbi, $template))
+ );
+
+ $_POST['drop_selected_dbs'] = '1';
+
+ $controller();
+ $actual = $response->getJSONResult();
+
+ $this->assertArrayHasKey('message', $actual);
+ $this->assertStringContainsString('<div class="alert alert-danger" role="alert">', $actual['message']);
+ $this->assertStringContainsString(__('No databases selected.'), $actual['message']);
+ }
+}
diff --git a/test/classes/Controllers/Server/DatabasesControllerTest.php b/test/classes/Controllers/Server/DatabasesControllerTest.php
index 40815e6718..0e60029bd4 100644
--- a/test/classes/Controllers/Server/DatabasesControllerTest.php
+++ b/test/classes/Controllers/Server/DatabasesControllerTest.php
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace PhpMyAdmin\Tests\Controllers\Server;
use PhpMyAdmin\Controllers\Server\DatabasesController;
-use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Relation;
use PhpMyAdmin\RelationCleanup;
use PhpMyAdmin\Template;
@@ -15,7 +14,6 @@ use PhpMyAdmin\Transformations;
use stdClass;
use function __;
-use function sprintf;
/**
* @covers \PhpMyAdmin\Controllers\Server\DatabasesController
@@ -64,7 +62,7 @@ class DatabasesControllerTest extends AbstractTestCase
);
$this->dummyDbi->addSelectDb('mysql');
- $controller->index();
+ $controller();
$this->assertAllSelectsConsumed();
$actual = $response->getHTMLResult();
@@ -101,7 +99,7 @@ class DatabasesControllerTest extends AbstractTestCase
$_REQUEST['sort_order'] = 'desc';
$this->dummyDbi->addSelectDb('mysql');
- $controller->index();
+ $controller();
$this->assertAllSelectsConsumed();
$actual = $response->getHTMLResult();
@@ -117,84 +115,4 @@ class DatabasesControllerTest extends AbstractTestCase
$this->assertStringContainsString('MiB', $actual);
$this->assertStringContainsString('name="db_collation"', $actual);
}
-
- public function testCreateDatabaseAction(): void
- {
- $response = new ResponseRenderer();
- $response->setAjax(true);
-
- $template = new Template();
- $transformations = new Transformations();
- $controller = new DatabasesController(
- $response,
- $template,
- $transformations,
- new RelationCleanup($this->dbi, new Relation($this->dbi, $template)),
- $this->dbi
- );
-
- $_POST['new_db'] = 'test_db_error';
-
- $controller->create();
- $actual = $response->getJSONResult();
-
- $this->assertArrayHasKey('message', $actual);
- $this->assertStringContainsString('<div class="alert alert-danger" role="alert">', $actual['message']);
-
- $response = new ResponseRenderer();
- $response->setAjax(true);
-
- $controller = new DatabasesController(
- $response,
- $template,
- $transformations,
- new RelationCleanup($this->dbi, new Relation($this->dbi, $template)),
- $this->dbi
- );
-
- $_POST['new_db'] = 'test_db';
- $_POST['db_collation'] = 'utf8_general_ci';
-
- $controller->create();
- $actual = $response->getJSONResult();
-
- $this->assertArrayHasKey('message', $actual);
- $this->assertStringContainsString('<div class="alert alert-success" role="alert">', $actual['message']);
- $this->assertStringContainsString(
- sprintf(__('Database %1$s has been created.'), 'test_db'),
- $actual['message']
- );
- }
-
- public function testDropDatabasesAction(): void
- {
- global $cfg;
-
- $dbi = $this->getMockBuilder(DatabaseInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $response = new ResponseRenderer();
- $response->setAjax(true);
-
- $cfg['AllowUserDropDatabase'] = true;
-
- $template = new Template();
- $controller = new DatabasesController(
- $response,
- $template,
- new Transformations(),
- new RelationCleanup($dbi, new Relation($dbi, $template)),
- $dbi
- );
-
- $_POST['drop_selected_dbs'] = '1';
-
- $controller->destroy();
- $actual = $response->getJSONResult();
-
- $this->assertArrayHasKey('message', $actual);
- $this->assertStringContainsString('<div class="alert alert-danger" role="alert">', $actual['message']);
- $this->assertStringContainsString(__('No databases selected.'), $actual['message']);
- }
}
diff --git a/test/classes/Stubs/DbiDummy.php b/test/classes/Stubs/DbiDummy.php
index eebc63d455..82632fa6cb 100644
--- a/test/classes/Stubs/DbiDummy.php
+++ b/test/classes/Stubs/DbiDummy.php
@@ -3026,6 +3026,119 @@ class DbiDummy implements DbiExtension
],
],
],
+ [
+ 'query' => 'SHOW TABLE STATUS FROM `world`',
+ 'columns' => [
+ 'Name',
+ 'Engine',
+ 'Version',
+ 'Row_format',
+ 'Rows',
+ 'Avg_row_length',
+ 'Data_length',
+ 'Max_data_length',
+ 'Index_length',
+ 'Data_free',
+ 'Auto_increment',
+ 'Create_time',
+ 'Update_time',
+ 'Check_time',
+ 'Collation',
+ 'Checksum',
+ 'Create_options',
+ 'Comment',
+ 'Max_index_length',
+ 'Temporary',
+ ],
+ 'result' => [
+ [
+ 'City',
+ 'InnoDB',
+ '10',
+ 'Dynamic',
+ '4046',
+ '101',
+ '409600',
+ '0',
+ '114688',
+ '0',
+ '4080',
+ '2020-07-03 17:24:47',
+ null,
+ null,
+ 'utf8mb4_general_ci',
+ null,
+ '',
+ '',
+ '0',
+ 'N',
+ ],
+ [
+ 'Country',
+ 'InnoDB',
+ '10',
+ 'Dynamic',
+ '239',
+ '479',
+ '114688',
+ '0',
+ '0',
+ '0',
+ null,
+ '2020-07-03 17:24:47',
+ null,
+ null,
+ 'utf8mb4_general_ci',
+ null,
+ '',
+ '',
+ '0',
+ 'N',
+ ],
+ [
+ 'CountryLanguage',
+ 'InnoDB',
+ '10',
+ 'Dynamic',
+ '984',
+ '99',
+ '98304',
+ '0',
+ '65536',
+ '0',
+ null,
+ '2020-07-03 17:24:47',
+ null,
+ null,
+ 'utf8mb4_general_ci',
+ null,
+ '',
+ '',
+ '0',
+ 'N',
+ ],
+ ],
+ ],
+ [
+ 'query' => 'SHOW TABLES FROM `world`;',
+ 'columns' => ['Tables_in_world'],
+ 'result' => [['City'], ['Country'], ['CountryLanguage']],
+ ],
+ [
+ 'query' => 'SELECT COUNT(*) AS `row_count` FROM `world`.`City`',
+ 'columns' => ['row_count'],
+ 'result' => [['4079']],
+ ],
+ [
+ 'query' => 'SELECT COUNT(*) AS `row_count` FROM `world`.`Country`',
+ 'columns' => ['row_count'],
+ 'result' => [['239']],
+ ],
+ [
+ 'query' => 'SELECT COUNT(*) AS `row_count` FROM `world`.`CountryLanguage`',
+ 'columns' => ['row_count'],
+ 'result' => [['984']],
+ ],
];
/* Some basic setup for dummy driver */