Merge pull request #16367 from mauriciofauth/central-columns

Refactor the CentralColumns class
This commit is contained in:
Maurício Meneghini Fauth 2020-09-25 15:36:31 -03:00 committed by GitHub
commit b252406f8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 77 additions and 318 deletions

View File

@ -193,13 +193,12 @@ AJAX.registerOnload('database/central_columns.js', function () {
$('#table-select').on('change', function () {
var selectValue = $(this).val();
var defaultColumnSelect = $('#column-select').find('option').first();
var href = 'index.php?route=/database/central-columns';
var href = 'index.php?route=/database/central-columns/populate';
var params = {
'ajax_request' : true,
'server' : CommonParams.get('server'),
'db' : CommonParams.get('db'),
'selectedTable' : selectValue,
'populateColumns' : true
'selectedTable' : selectValue
};
$('#column-select').html('<option value="">' + Messages.strLoading + '</option>');
if (selectValue !== '') {

View File

@ -9,7 +9,6 @@ namespace PhpMyAdmin;
use PhpMyAdmin\Charsets\Charset;
use PhpMyAdmin\Charsets\Collation;
use PhpMyAdmin\Html\Generator;
use function array_unique;
use function bin2hex;
use function ceil;
@ -235,20 +234,6 @@ class CentralColumns
return $has_list;
}
/**
* return error message to be displayed if central columns
* configuration storage is not completely configured
*/
private function configErrorMessage(): Message
{
return Message::error(
__(
'The configuration storage is not ready for the central list'
. ' of columns feature.'
)
);
}
/**
* build the insert query for central columns list given PMA storage
* db, central_columns table, column name and corresponding definition to be added
@ -316,7 +301,9 @@ class CentralColumns
) {
$cfgCentralColumns = $this->getParams();
if (! is_array($cfgCentralColumns)) {
return $this->configErrorMessage();
return Message::error(
__('The configuration storage is not ready for the central list of columns feature.')
);
}
$db = $_POST['db'];
$pmadb = $cfgCentralColumns['db'];
@ -438,7 +425,9 @@ class CentralColumns
) {
$cfgCentralColumns = $this->getParams();
if (! is_array($cfgCentralColumns)) {
return $this->configErrorMessage();
return Message::error(
__('The configuration storage is not ready for the central list of columns feature.')
);
}
$pmadb = $cfgCentralColumns['db'];
$central_list_table = $cfgCentralColumns['table'];
@ -659,7 +648,9 @@ class CentralColumns
) {
$cfgCentralColumns = $this->getParams();
if (! is_array($cfgCentralColumns)) {
return $this->configErrorMessage();
return Message::error(
__('The configuration storage is not ready for the central list of columns feature.')
);
}
$centralTable = $cfgCentralColumns['table'];
$this->dbi->selectDb($cfgCentralColumns['db'], DatabaseInterface::CONNECT_CONTROL);
@ -741,19 +732,6 @@ class CentralColumns
return true;
}
/**
* Function generate and return the table header for
* multiple edit central columns page
*
* @param array $headers headers list
*
* @return string html for table header in central columns multi edit page
*/
private function getEditTableHeader(array $headers): string
{
return $this->template->render('database/central_columns/edit_table_header', ['headers' => $headers]);
}
/**
* build html for editing a row in central columns table
*
@ -857,49 +835,6 @@ class CentralColumns
return $columns_list;
}
/**
* Get HTML for "check all" check box with "with selected" dropdown
*
* @param string $themeImagePath pma theme image url
* @param string $text_dir url for text directory
*/
public function getTableFooter(string $themeImagePath, string $text_dir): string
{
$html_output = $this->template->render('select_all', [
'theme_image_path' => $themeImagePath,
'text_dir' => $text_dir,
'form_name' => 'tableslistcontainer',
]);
$html_output .= '<button class="btn btn-link mult_submit change_central_columns" type="submit"'
. ' name="edit_central_columns" value="edit central columns"'
. ' title="' . __('Edit') . '">' . "\n"
. Generator::getIcon('b_edit', __('Edit'))
. '</button>' . "\n";
$html_output .= '<button class="btn btn-link mult_submit" type="submit"'
. ' name="delete_central_columns" value="remove_from_central_columns"'
. ' title="' . __('Delete') . '">' . "\n"
. Generator::getIcon('b_drop', __('Delete'))
. '</button>' . "\n";
return $html_output;
}
/**
* function generate and return the table footer for
* multiple edit central columns page
*
* @return string html for table footer in central columns multi edit page
*/
private function getEditTableFooter(): string
{
return '<fieldset class="tblFooters">'
. '<input class="btn btn-primary" type="submit" '
. 'name="save_multi_central_column_edit" value="' . __('Save') . '">'
. '</fieldset>';
}
/**
* Column `col_extra` is used to store both extra and attributes for a column.
* This method separates them.
@ -941,18 +876,7 @@ class CentralColumns
*/
public function getHtmlForEditingPage(array $selected_fld, string $selected_db): string
{
$html = '<form id="multi_edit_central_columns">';
$header_cells = [
__('Name'),
__('Type'),
__('Length/Values'),
__('Default'),
__('Collation'),
__('Attributes'),
__('Null'),
__('A_I'),
];
$html .= $this->getEditTableHeader($header_cells);
$html = '';
$selected_fld_safe = [];
foreach ($selected_fld as $key) {
$selected_fld_safe[] = $this->dbi->escapeString($key);
@ -969,9 +893,6 @@ class CentralColumns
$html .= $tableHtmlRow;
$row_num++;
}
$html .= '</table>';
$html .= $this->getEditTableFooter();
$html .= '</form>';
return $html;
}
@ -1015,38 +936,28 @@ class CentralColumns
}
/**
* build dropdown select html to select column in selected table,
* include only columns which are not already in central list
*
* @param string $db current database to which selected table belongs
* @param string $selected_tbl selected table
*
* @return string html to select column
* @return string[]
*/
public function getHtmlForColumnDropdown($db, $selected_tbl)
public function getColumnsNotInCentralList(string $db, string $table): array
{
$existing_cols = $this->getFromTable($db, $selected_tbl);
$existingColumns = $this->getFromTable($db, $table);
$this->dbi->selectDb($db);
$columns = (array) $this->dbi->getColumnNames(
$db,
$selected_tbl
);
$selectColHtml = '';
foreach ($columns as $column) {
if (in_array($column, $existing_cols)) {
$columnNames = (array) $this->dbi->getColumnNames($db, $table);
$columns = [];
foreach ($columnNames as $column) {
if (in_array($column, $existingColumns)) {
continue;
}
$selectColHtml .= '<option value="' . htmlspecialchars($column) . '">'
. htmlspecialchars($column)
. '</option>';
$columns[] = $column;
}
return $selectColHtml;
return $columns;
}
/**
* build html for adding a new user defined column to central list
* Adding a new user defined column to central list
*
* @param string $db current database
* @param int $total_rows number of rows in central columns
@ -1054,16 +965,15 @@ class CentralColumns
* @param string $themeImagePath table footer theme image directorie
* @param string $text_dir table footer arrow direction
*
* @return string html of the form to let user add a new user defined column to the
* list
* @return array
*/
public function getHtmlForMain(
public function getTemplateVariablesForMain(
string $db,
int $total_rows,
int $pos,
string $themeImagePath,
string $text_dir
): string {
): array {
$max_rows = $this->maxRows;
$attribute_types = $this->dbi->types->getAttributes();
@ -1132,7 +1042,7 @@ class CentralColumns
];
}
return $this->template->render('database/central_columns/main', [
return [
'db' => $db,
'total_rows' => $total_rows,
'max_rows' => $max_rows,
@ -1149,6 +1059,6 @@ class CentralColumns
'theme_image_path' => $themeImagePath,
'text_dir' => $text_dir,
'charsets' => $charsetsList,
]);
];
}
}

View File

@ -69,13 +69,6 @@ class CentralColumnsController extends AbstractController
'collation' => $_POST['collation'] ?? null,
]);
}
if (isset($_POST['populateColumns'])) {
$this->response->addHTML($this->populateColumns([
'selectedTable' => $_POST['selectedTable'],
]));
return;
}
if (isset($_POST['getColumnList'])) {
$this->response->addJSON('message', $this->getColumnList([
'cur_table' => $_POST['cur_table'] ?? null,
@ -97,10 +90,10 @@ class CentralColumnsController extends AbstractController
]);
if (isset($_POST['edit_central_columns_page'])) {
$this->response->addHTML($this->editPage([
$this->editPage([
'selected_fld' => $_POST['selected_fld'] ?? null,
'db' => $_POST['db'] ?? null,
]));
]);
return;
}
@ -130,10 +123,10 @@ class CentralColumnsController extends AbstractController
]);
}
$this->response->addHTML($this->main([
$this->main([
'pos' => $_POST['pos'] ?? null,
'total_rows' => $_POST['total_rows'] ?? null,
]));
]);
$pos = 0;
if (Core::isValid($_POST['pos'], 'integer')) {
@ -156,10 +149,8 @@ class CentralColumnsController extends AbstractController
/**
* @param array $params Request parameters
*
* @return string HTML
*/
public function main(array $params): string
public function main(array $params): void
{
global $text_dir, $PMA_Theme;
@ -176,13 +167,15 @@ class CentralColumnsController extends AbstractController
$pos = (int) $params['pos'];
}
return $this->centralColumns->getHtmlForMain(
$variables = $this->centralColumns->getTemplateVariablesForMain(
$this->db,
$totalRows,
$pos,
$PMA_Theme->getImgPath(),
$text_dir
);
$this->render('database/central_columns/main', $variables);
}
/**
@ -198,17 +191,10 @@ class CentralColumnsController extends AbstractController
);
}
/**
* @param array $params Request parameters
*
* @return string HTML
*/
public function populateColumns(array $params): string
public function populateColumns(): void
{
return $this->centralColumns->getHtmlForColumnDropdown(
$this->db,
$params['selectedTable']
);
$columns = $this->centralColumns->getColumnsNotInCentralList($this->db, $_POST['selectedTable']);
$this->render('database/central_columns/populate_columns', ['columns' => $columns]);
}
/**
@ -279,15 +265,15 @@ class CentralColumnsController extends AbstractController
/**
* @param array $params Request parameters
*
* @return string HTML
*/
public function editPage(array $params): string
public function editPage(array $params): void
{
return $this->centralColumns->getHtmlForEditingPage(
$rows = $this->centralColumns->getHtmlForEditingPage(
$params['selected_fld'],
$params['db']
);
$this->render('database/central_columns/edit', ['rows' => $rows]);
}
/**

View File

@ -118,7 +118,10 @@ return static function (RouteCollector $routes): void {
$routes->get('/changelog', [ChangeLogController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/check-relations', [CheckRelationsController::class, 'index']);
$routes->addGroup('/database', static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/central-columns', [CentralColumnsController::class, 'index']);
$routes->addGroup('/central-columns', static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '', [CentralColumnsController::class, 'index']);
$routes->post('/populate', [CentralColumnsController::class, 'populateColumns']);
});
$routes->get('/data-dictionary', [DataDictionaryController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/designer', [DesignerController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/events', [EventsController::class, 'index']);

View File

@ -0,0 +1,22 @@
<form id="multi_edit_central_columns">
<table id="table_columns" class="noclick">
<caption class="tblHeaders">{% trans 'Structure' %}</caption>
<thead>
<tr>
<th>{% trans 'Name' %}</th>
<th>{% trans 'Type' %}</th>
<th>{% trans 'Length/Values' %}</th>
<th>{% trans 'Default' %}</th>
<th>{% trans 'Collation' %}</th>
<th>{% trans 'Attributes' %}</th>
<th>{% trans 'Null' %}</th>
<th>{% trans %}A_I{% context %}Auto Increment{% endtrans %}</th>
</tr>
</thead>
{{ rows|raw }}
</table>
<fieldset class="tblFooters">
<input class="btn btn-primary" type="submit" name="save_multi_central_column_edit" value="{% trans 'Save' %}">
</fieldset>
</form>

View File

@ -1,9 +0,0 @@
<table id="table_columns" class="noclick">
<caption class="tblHeaders">{% trans 'Structure' %}</caption>
<thead>
<tr>
{% for header in headers %}
<th>{{ header }}</th>
{% endfor %}
</tr>
</thead>

View File

@ -371,7 +371,7 @@
{% endfor %}
</tbody>
</table>
{# getTableFooter #}
{% include 'select_all.twig' with {
'theme_image_path': theme_image_path,
'text_dir' : text_dir,

View File

@ -0,0 +1,3 @@
{% for column in columns %}
<option value="{{ column }}">{{ column }}</option>
{% endfor %}

View File

@ -9,13 +9,9 @@ namespace PhpMyAdmin\Tests;
use PhpMyAdmin\CentralColumns;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Message;
use PhpMyAdmin\Types;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use function array_slice;
use function ceil;
/**
* tests for PhpMyAdmin\CentralColumns
@ -491,29 +487,6 @@ class CentralColumnsTest extends AbstractTestCase
],
'phpmyadmin'
);
$this->assertStringContainsString(
'<form',
$result
);
$header_cells = [
__('Name'),
__('Type'),
__('Length/Values'),
__('Default'),
__('Collation'),
__('Attributes'),
__('Null'),
__('A_I'),
];
$this->assertStringContainsString(
$this->callFunction(
$this->centralColumns,
CentralColumns::class,
'getEditTableHeader',
[$header_cells]
),
$result
);
$list_detail_cols = $this->callFunction(
$this->centralColumns,
CentralColumns::class,
@ -536,10 +509,6 @@ class CentralColumnsTest extends AbstractTestCase
),
$result
);
$this->assertStringContainsString(
$this->callFunction($this->centralColumns, CentralColumns::class, 'getEditTableFooter', []),
$result
);
}
/**
@ -595,100 +564,6 @@ class CentralColumnsTest extends AbstractTestCase
);
}
/**
* Test for getHtmlForMain
*/
public function testGetHtmlForMain(): void
{
$db = 'phpmyadmin';
$total_rows = 50;
$pos = 26;
$themeImagePath = 'themeImagePath';
$text_dir = 'text_dir';
$max_rows = (int) $GLOBALS['cfg']['MaxRows'];
// test for not empty table
$result = $this->centralColumns->getHtmlForMain(
$db,
$total_rows,
$pos,
$themeImagePath,
$text_dir
);
$this->assertStringContainsString(
'<form action="index.php?route=/database/central-columns',
$result
);
$this->assertStringContainsString(
'" method="post">',
$result
);
$this->assertStringContainsString(
Url::getHiddenInputs(
'phpmyadmin'
),
$result
);
$this->assertStringContainsString(
'<input class="btn btn-secondary ajax" type="submit" name="navig" value="&lt">',
$result
);
$this->assertStringContainsString(
Util::pageselector(
'pos',
$max_rows,
($pos / $max_rows) + 1,
(int) ceil($total_rows / $max_rows)
),
$result
);
$this->assertStringContainsString('<span>+', $result);
$this->assertStringContainsString('class="new_central_col hide"', $result);
$this->assertStringContainsString(__('Filter rows') . ':', $result);
$this->assertStringContainsString(__('Add column'), $result);
$this->assertStringContainsString(__('Click to sort.'), $result);
$this->assertStringContainsString(Url::getHiddenInputs($db), $result);
$this->assertStringContainsString(Url::getHiddenInputs($db), $result);
$editSelectedButton = ' <button class="btn btn-link mult_submit change_central_columns"'
. ' type="submit" name="edit_central_columns"' . "\n"
. ' value="edit central columns" title="' . __('Edit') . '">' . "\n"
. ' ' . Generator::getIcon('b_edit', __('Edit')) . "\n"
. ' </button>' . "\n";
$deleteSelectedButton = ' <button class="btn btn-link mult_submit" type="submit"'
. ' name="delete_central_columns"' . "\n"
. ' value="remove_from_central_columns" title="' . __('Delete') . '">' . "\n"
. ' ' . Generator::getIcon('b_drop', __('Delete')) . "\n"
. ' </button>' . "\n";
$this->assertStringContainsString($editSelectedButton, $result);
$this->assertStringContainsString($deleteSelectedButton, $result);
// test for empty table
$total_rows = 0;
$result = $this->centralColumns->getHtmlForMain(
$db,
$total_rows,
$pos,
$themeImagePath,
$text_dir
);
$this->assertStringContainsString('<span>-', $result);
$this->assertStringContainsString('class="new_central_col"', $result);
$this->assertStringContainsString(__('Add column'), $result);
$this->assertStringContainsString(Url::getHiddenInputs($db), $result);
$this->assertStringContainsString(__('The central list of columns for the current database is empty'), $result);
}
/**
* Test for configErrorMessage
*/
public function testConfigErrorMessage(): void
{
$this->assertInstanceOf(
Message::class,
$this->callFunction($this->centralColumns, CentralColumns::class, 'configErrorMessage', [])
);
}
/**
* Test for findExistingColNames
*/
@ -721,40 +596,10 @@ class CentralColumnsTest extends AbstractTestCase
);
}
/**
* Test for getTableFooter
*/
public function testGetTableFooter(): void
public function testGetColumnsNotInCentralList(): void
{
$themeImagePath = 'themeImagePath';
$text_dir = 'text_dir';
$result = $this->centralColumns->getTableFooter($themeImagePath, $text_dir);
$this->assertStringContainsString(
'<input type="checkbox" id="tableslistcontainer_checkall" class="checkall_box"',
$result
);
$this->assertStringContainsString('With selected:', $result);
$this->assertStringContainsString(
'<button class="btn btn-link mult_submit change_central_columns"',
$result
);
}
/**
* Test for getHtmlForColumnDropdown
*/
public function testGetHtmlForColumnDropdown(): void
{
$db = 'PMA_db';
$selected_tbl = 'PMA_table';
$result = $this->centralColumns->getHtmlForColumnDropdown(
$db,
$selected_tbl
);
$this->assertEquals(
'<option value="id">id</option><option value="col1">col1</option>'
. '<option value="col2">col2</option>',
$result
);
$columns = $this->centralColumns->getColumnsNotInCentralList('PMA_db', 'PMA_table');
$this->assertIsArray($columns);
$this->assertEquals(['id', 'col1', 'col2'], $columns);
}
}