From c4421d064d16df3da41690c6925b3eb89a1ef282 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 13 May 2023 22:58:26 +0100 Subject: [PATCH 1/9] Improve type hint Signed-off-by: Kamil Tekiela --- libraries/classes/ConfigStorage/Relation.php | 4 ++-- libraries/classes/InsertEdit.php | 14 +++++++------- phpstan-baseline.neon | 13 +++++++++---- psalm-baseline.xml | 6 ++++-- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/libraries/classes/ConfigStorage/Relation.php b/libraries/classes/ConfigStorage/Relation.php index 0eef61ad9e..0ec7b66242 100644 --- a/libraries/classes/ConfigStorage/Relation.php +++ b/libraries/classes/ConfigStorage/Relation.php @@ -531,7 +531,7 @@ class Relation * @param string $db the name of the db to check for * @param string $table the name of the table to check for * - * @return mixed[] [column_name] = comment + * @return string[] [column_name] = comment */ public function getComments(string $db, string $table = ''): array { @@ -544,7 +544,7 @@ class Relation // MySQL native column comments $columns = $this->dbi->getColumns($db, $table, true); foreach ($columns as $column) { - if (empty($column['Comment'])) { + if ($column['Comment'] === '') { continue; } diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index a0429bdff4..913be60da5 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -304,8 +304,8 @@ class InsertEdit /** * Analyze the table column array * - * @param mixed[] $column description of column in given table - * @param mixed[] $commentsMap comments for every column that has a comment + * @param mixed[] $column description of column in given table + * @param string[] $commentsMap comments for every column that has a comment * * @return mixed[] description of column in given table */ @@ -350,8 +350,8 @@ class InsertEdit /** * Retrieve the column title * - * @param mixed[] $column description of column in given table - * @param mixed[] $commentsMap comments for every column that has a comment + * @param mixed[] $column description of column in given table + * @param string[] $commentsMap comments for every column that has a comment * * @return string column title */ @@ -1600,7 +1600,7 @@ class InsertEdit * @param string $db current database * @param string $table current table * - * @return mixed[] comments for columns + * @return string[] comments for columns */ public function getCommentsMap(string $db, string $table): array { @@ -1657,7 +1657,7 @@ class InsertEdit * * @param mixed[] $column column * @param int $columnNumber column index in table_columns - * @param mixed[] $commentsMap comments map + * @param string[] $commentsMap comments map * @param ResultInterface $currentResult current result * @param bool $insertMode whether insert mode * @param mixed[] $currentRow current row @@ -2000,7 +2000,7 @@ class InsertEdit * * @param mixed[] $urlParams url parameters * @param mixed[][] $tableColumns table columns - * @param mixed[] $commentsMap comments map + * @param string[] $commentsMap comments map * @param ResultInterface $currentResult current result * @param bool $insertMode whether insert mode * @param mixed[] $currentRow current row diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d7ce321683..c2c9d86a5f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -655,6 +655,11 @@ parameters: count: 1 path: libraries/classes/ConfigStorage/Relation.php + - + message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getComments\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: libraries/classes/ConfigStorage/Relation.php + - message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getDisplayField\\(\\) should return string but returns mixed\\.$#" count: 1 @@ -4657,7 +4662,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 3 + count: 2 path: libraries/classes/InsertEdit.php - @@ -5342,7 +5347,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 8 + count: 7 path: libraries/classes/Plugins/Export/ExportHtmlword.php - @@ -5482,7 +5487,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 9 + count: 8 path: libraries/classes/Plugins/Export/ExportOdt.php - @@ -5727,7 +5732,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 5 + count: 4 path: libraries/classes/Plugins/Export/ExportTexytext.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 7d21c3adf6..b31306e399 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -784,6 +784,10 @@ $foreigners[$column] + + $comments + string[] + $attributes[$rownum] $columnsList[] $field - $rowComments[$rownum] @@ -7651,7 +7654,6 @@ - $currCellEditedValues[$columnName] From 3b611f39451cc843fe5965fd939d1da79aad59ad Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 00:23:43 +0100 Subject: [PATCH 2/9] Implement ColumnFull DTO This is MVP. In following commits the DTO will be expanded and improved. Signed-off-by: Kamil Tekiela --- libraries/classes/ColumnFull.php | 21 +++ .../Controllers/Table/ChangeController.php | 4 +- libraries/classes/InsertEdit.php | 115 +++++++----- phpstan-baseline.neon | 52 ++++-- psalm-baseline.xml | 15 +- test/classes/InsertEditTest.php | 173 +++++++----------- 6 files changed, 206 insertions(+), 174 deletions(-) create mode 100644 libraries/classes/ColumnFull.php diff --git a/libraries/classes/ColumnFull.php b/libraries/classes/ColumnFull.php new file mode 100644 index 0000000000..06536b56d8 --- /dev/null +++ b/libraries/classes/ColumnFull.php @@ -0,0 +1,21 @@ +urlParamsInEditMode($GLOBALS['urlParams'], $whereClauseArray); $hasBlobField = false; - foreach ($tableColumns as $column) { - if ($this->insertEdit->isColumn($column, ['blob', 'tinyblob', 'mediumblob', 'longblob'])) { + foreach ($tableColumns as $tableColumn) { + if ($this->insertEdit->isColumn($tableColumn->type, ['blob', 'tinyblob', 'mediumblob', 'longblob'])) { $hasBlobField = true; break; } diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 913be60da5..531275d775 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -15,7 +15,6 @@ use function __; use function array_fill; use function array_key_exists; use function array_merge; -use function array_values; use function bin2hex; use function class_exists; use function count; @@ -304,36 +303,47 @@ class InsertEdit /** * Analyze the table column array * - * @param mixed[] $column description of column in given table - * @param string[] $commentsMap comments for every column that has a comment + * @param ColumnFull $tableColumn description of column in given table + * @param string[] $commentsMap comments for every column that has a comment * * @return mixed[] description of column in given table */ private function analyzeTableColumnsArray( - array $column, + ColumnFull $tableColumn, array $commentsMap, ): array { - $column['Field_md5'] = md5($column['Field']); + $column = [ + 'Field' => $tableColumn->field, + 'Type' => $tableColumn->type, + 'Collation' => $tableColumn->collation, + 'Null' => $tableColumn->isNull ? 'YES' : 'NO', + 'Key' => $tableColumn->key, + 'Default' => $tableColumn->default, + 'Extra' => $tableColumn->extra, + 'Privileges' => $tableColumn->privileges, + 'Comment' => $tableColumn->comment, + ]; + $column['Field_md5'] = md5($tableColumn->field); // True_Type contains only the type (stops at first bracket) - $column['True_Type'] = preg_replace('@\(.*@s', '', $column['Type']); - $column['len'] = preg_match('@float|double@', $column['Type']) ? 100 : -1; - $column['Field_title'] = $this->getColumnTitle($column, $commentsMap); + $column['True_Type'] = preg_replace('@\(.*@s', '', $tableColumn->type); + $column['len'] = preg_match('@float|double@', $tableColumn->type) ? 100 : -1; + $column['Field_title'] = $this->getColumnTitle($tableColumn->field, $commentsMap); $column['is_binary'] = $this->isColumn( - $column, + $tableColumn->type, ['binary', 'varbinary'], ); $column['is_blob'] = $this->isColumn( - $column, + $tableColumn->type, ['blob', 'tinyblob', 'mediumblob', 'longblob'], ); $column['is_char'] = $this->isColumn( - $column, + $tableColumn->type, ['char', 'varchar'], ); $column['pma_type'] = match ($column['True_Type']) { 'set', 'enum' => $column['True_Type'], - default => $column['Type'] + default => $tableColumn->type, }; $column['wrap'] = match ($column['True_Type']) { @@ -350,20 +360,20 @@ class InsertEdit /** * Retrieve the column title * - * @param mixed[] $column description of column in given table + * @param string $fieldName name of the column * @param string[] $commentsMap comments for every column that has a comment * * @return string column title */ - private function getColumnTitle(array $column, array $commentsMap): string + private function getColumnTitle(string $fieldName, array $commentsMap): string { - if (isset($commentsMap[$column['Field']])) { + if (isset($commentsMap[$fieldName])) { return '' - . htmlspecialchars($column['Field']) . ''; + . htmlspecialchars($commentsMap[$fieldName]) . '">' + . htmlspecialchars($fieldName) . ''; } - return htmlspecialchars($column['Field']); + return htmlspecialchars($fieldName); } /** @@ -371,13 +381,13 @@ class InsertEdit * the goal is to ensure that types such as "enum('one','two','binary',..)" * or "enum('one','two','varbinary',..)" are not categorized as binary * - * @param mixed[] $column description of column in given table - * @param string[] $types the types to verify + * @param string $columnType column type as specified in the column definition + * @param string[] $types the types to verify */ - public function isColumn(array $column, array $types): bool + public function isColumn(string $columnType, array $types): bool { foreach ($types as $oneType) { - if (mb_stripos($column['Type'], $oneType) === 0) { + if (mb_stripos($columnType, $oneType) === 0) { return true; } } @@ -1503,13 +1513,28 @@ class InsertEdit * @param string $db current db * @param string $table current table * - * @return mixed[][] + * @return list */ public function getTableColumns(string $db, string $table): array { $this->dbi->selectDb($db); - return array_values($this->dbi->getColumns($db, $table, true)); + $columns = []; + foreach ($this->dbi->getColumns($db, $table, true) as $column) { + $columns[] = new ColumnFull( + $column['Field'], + $column['Type'], + $column['Collation'], + $column['Null'] === 'YES', + $column['Key'], + $column['Default'], + $column['Extra'], + $column['Privileges'], + $column['Comment'], + ); + } + + return $columns; } /** @@ -1655,7 +1680,7 @@ class InsertEdit /** * Function to get html for each insert/edit column * - * @param mixed[] $column column + * @param ColumnFull $tableColumn column * @param int $columnNumber column index in table_columns * @param string[] $commentsMap comments map * @param ResultInterface $currentResult current result @@ -1674,7 +1699,7 @@ class InsertEdit * @param string $whereClause the where clause */ private function getHtmlForInsertEditFormColumn( - array $column, + ColumnFull $tableColumn, int $columnNumber, array $commentsMap, ResultInterface $currentResult, @@ -1692,9 +1717,7 @@ class InsertEdit array $columnMime, string $whereClause, ): string { - if (! isset($column['processed'])) { - $column = $this->analyzeTableColumnsArray($column, $commentsMap); - } + $column = $this->analyzeTableColumnsArray($tableColumn, $commentsMap); $asIs = false; /** @var string $fieldHashMd5 */ @@ -1998,20 +2021,20 @@ class InsertEdit /** * Function to get html for each insert/edit row * - * @param mixed[] $urlParams url parameters - * @param mixed[][] $tableColumns table columns - * @param string[] $commentsMap comments map - * @param ResultInterface $currentResult current result - * @param bool $insertMode whether insert mode - * @param mixed[] $currentRow current row - * @param bool $isUpload whether upload - * @param mixed[] $foreigners foreigners - * @param string $table table - * @param string $db database - * @param int $rowId row id - * @param string $textDir text direction - * @param mixed[] $repopulate the data to be repopulated - * @param mixed[] $whereClauseArray the array of where clauses + * @param mixed[] $urlParams url parameters + * @param list $tableColumns table columns + * @param string[] $commentsMap comments map + * @param ResultInterface $currentResult current result + * @param bool $insertMode whether insert mode + * @param mixed[] $currentRow current row + * @param bool $isUpload whether upload + * @param mixed[] $foreigners foreigners + * @param string $table table + * @param string $db database + * @param int $rowId row id + * @param string $textDir text direction + * @param mixed[] $repopulate the data to be repopulated + * @param mixed[] $whereClauseArray the array of where clauses */ public function getHtmlForInsertEditRow( array $urlParams, @@ -2044,12 +2067,12 @@ class InsertEdit for ($columnNumber = 0; $columnNumber < $columnCount; $columnNumber++) { $tableColumn = $tableColumns[$columnNumber]; $columnMime = []; - if (isset($mimeMap[$tableColumn['Field']])) { - $columnMime = $mimeMap[$tableColumn['Field']]; + if (isset($mimeMap[$tableColumn->field])) { + $columnMime = $mimeMap[$tableColumn->field]; } $virtual = ['VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED']; - if (in_array($tableColumn['Extra'], $virtual)) { + if (in_array($tableColumn->extra, $virtual)) { continue; } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c2c9d86a5f..ba99b96288 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -4615,13 +4615,18 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php + - + message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + - message: "#^Parameter \\#1 \\$data of static method PhpMyAdmin\\\\Utils\\\\Gis\\:\\:convertToWellKnownText\\(\\) expects string, mixed given\\.$#" count: 1 path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#1 \\$haystack of function mb_stripos expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$field of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" count: 1 path: libraries/classes/InsertEdit.php @@ -4660,16 +4665,6 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php - - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, mixed given\\.$#" - count: 2 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#1 \\$string of function md5 expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, mixed given\\.$#" count: 1 @@ -4715,11 +4710,46 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php + - + message: "#^Parameter \\#2 \\$type of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Parameter \\#3 \\$collation of class PhpMyAdmin\\\\ColumnFull constructor expects string\\|null, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + - message: "#^Parameter \\#3 \\$row of static method PhpMyAdmin\\\\Util\\:\\:getUniqueCondition\\(\\) expects array\\, mixed given\\.$#" count: 1 path: libraries/classes/InsertEdit.php + - + message: "#^Parameter \\#5 \\$key of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Parameter \\#6 \\$default of class PhpMyAdmin\\\\ColumnFull constructor expects string\\|null, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Parameter \\#7 \\$extra of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Parameter \\#8 \\$privileges of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Parameter \\#9 \\$comment of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + - message: "#^Binary operation \"\\-\" between string and 1 results in an error\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index b31306e399..d765275bac 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7630,12 +7630,16 @@ + + + + - - + + @@ -7647,8 +7651,6 @@ - - @@ -7700,8 +7702,6 @@ - - @@ -7724,12 +7724,9 @@ - - $columnSetValues - $currCellEditedValues diff --git a/test/classes/InsertEditTest.php b/test/classes/InsertEditTest.php index a36373be94..af6ae0a915 100644 --- a/test/classes/InsertEditTest.php +++ b/test/classes/InsertEditTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests; +use PhpMyAdmin\ColumnFull; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; @@ -413,7 +414,7 @@ class InsertEditTest extends AbstractTestCase */ public function testAnalyzeTableColumnsArray(): void { - $column = ['Field' => '1<2', 'Field_md5' => 'pswd', 'Type' => 'float(10, 1)']; + $column = new ColumnFull('1<2', 'float(10, 1)', null, false, '', null, '', '', ''); $result = $this->callFunction( $this->insertEdit, @@ -448,15 +449,14 @@ class InsertEditTest extends AbstractTestCase */ public function testGetColumnTitle(): void { - $column = []; - $column['Field'] = 'f1<'; + $fieldName = 'f1<'; $this->assertEquals( $this->callFunction( $this->insertEdit, InsertEdit::class, 'getColumnTitle', - [$column, []], + [$fieldName, []], ), 'f1<', ); @@ -468,7 +468,7 @@ class InsertEditTest extends AbstractTestCase $this->insertEdit, InsertEdit::class, 'getColumnTitle', - [$column, $comments], + [$fieldName, $comments], ); $result = $this->parseString($result); @@ -483,51 +483,50 @@ class InsertEditTest extends AbstractTestCase */ public function testIsColumn(): void { - $column = []; $types = ['binary', 'varbinary']; - $column['Type'] = 'binaryfoo'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'binaryfoo'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'Binaryfoo'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'Binaryfoo'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'varbinaryfoo'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'varbinaryfoo'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'barbinaryfoo'; - $this->assertFalse($this->insertEdit->isColumn($column, $types)); + $columnType = 'barbinaryfoo'; + $this->assertFalse($this->insertEdit->isColumn($columnType, $types)); $types = ['char', 'varchar']; - $column['Type'] = 'char(10)'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'char(10)'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'VarChar(20)'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'VarChar(20)'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'foochar'; - $this->assertFalse($this->insertEdit->isColumn($column, $types)); + $columnType = 'foochar'; + $this->assertFalse($this->insertEdit->isColumn($columnType, $types)); $types = ['blob', 'tinyblob', 'mediumblob', 'longblob']; - $column['Type'] = 'blob'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'blob'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'bloB'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'bloB'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'mediumBloB'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'mediumBloB'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'tinyblobabc'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'tinyblobabc'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'longblob'; - $this->assertTrue($this->insertEdit->isColumn($column, $types)); + $columnType = 'longblob'; + $this->assertTrue($this->insertEdit->isColumn($columnType, $types)); - $column['Type'] = 'foolongblobbar'; - $this->assertFalse($this->insertEdit->isColumn($column, $types)); + $columnType = 'foolongblobbar'; + $this->assertFalse($this->insertEdit->isColumn($columnType, $types)); } /** @@ -2218,7 +2217,30 @@ class InsertEditTest extends AbstractTestCase $dbi->expects($this->once()) ->method('getColumns') ->with('db', 'table') - ->will($this->returnValue([['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g' => 'h']])); + ->will($this->returnValue([ + [ + 'Field' => 'b', + 'Type' => 'd', + 'Collation' => null, + 'Null' => 'NO', + 'Key' => '', + 'Default' => null, + 'Extra' => '', + 'Privileges' => '', + 'Comment' => '', + ], + [ + 'Field' => 'f', + 'Type' => 'h', + 'Collation' => null, + 'Null' => 'YES', + 'Key' => '', + 'Default' => null, + 'Extra' => '', + 'Privileges' => '', + 'Comment' => '', + ], + ])); $GLOBALS['dbi'] = $dbi; $this->insertEdit = new InsertEdit( @@ -2232,7 +2254,10 @@ class InsertEditTest extends AbstractTestCase $result = $this->insertEdit->getTableColumns('db', 'table'); $this->assertEquals( - [['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g' => 'h']], + [ + new ColumnFull('b', 'd', null, false, '', null, '', '', ''), + new ColumnFull('f', 'h', null, true, '', null, '', '', ''), + ], $result, ); } @@ -2379,12 +2404,7 @@ class InsertEditTest extends AbstractTestCase $_SESSION[' HMAC_secret '] = hash('sha1', 'test'); $GLOBALS['plugin_scripts'] = []; $foreigners = ['foreign_keys_data' => []]; - $tableColumn = [ - 'Field' => 'col', - 'Type' => 'varchar(20)', - 'Null' => 'Yes', - 'Privileges' => 'insert,update,select', - ]; + $tableColumn = new ColumnFull('col', 'varchar(20)', null, true, '', null, '', 'insert,update,select', ''); $repopulate = [md5('col') => 'val']; $columnMime = [ 'input_transformation' => 'Input/Image_JPEG_Upload.php', @@ -2440,15 +2460,7 @@ class InsertEditTest extends AbstractTestCase ); // Test w/o input_transformation - $tableColumn = [ - 'Field' => 'qwerty', - 'Type' => 'datetime', - 'Null' => 'Yes', - 'Key' => '', - 'Extra' => '', - 'Default' => null, - 'Privileges' => 'insert,update,select', - ]; + $tableColumn = new ColumnFull('qwerty', 'datetime', null, true, '', null, '', 'insert,update,select', ''); $repopulate = [md5('qwerty') => '12-10-14']; $actual = $this->callFunction( $this->insertEdit, @@ -2537,15 +2549,7 @@ class InsertEditTest extends AbstractTestCase $GLOBALS['cfg']['TextareaCols'] = 11; $foreigners = ['foreign_keys_data' => []]; $tableColumns = [ - [ - 'Field' => 'test', - 'Extra' => '', - 'Type' => 'longtext', - 'Null' => 'Yes', - 'pma_type' => 'longtext', - 'True_Type' => 'longtext', - 'Privileges' => 'select,insert,update,references', - ], + new ColumnFull('test', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''), ]; $resultStub = $this->createMock(DummyResult::class); @@ -2593,24 +2597,8 @@ class InsertEditTest extends AbstractTestCase // edit $tableColumns = [ - [ - 'Field' => 'foo', - 'Type' => 'longtext', - 'Extra' => '', - 'Null' => 'Yes', - 'pma_type' => 'longtext', - 'True_Type' => 'longtext', - 'Privileges' => 'select,insert,update,references', - ], - [ - 'Field' => 'bar', - 'Type' => 'longtext', - 'Extra' => '', - 'Null' => 'Yes', - 'pma_type' => 'longtext', - 'True_Type' => 'longtext', - 'Privileges' => 'select,insert,references', - ], + new ColumnFull('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''), + new ColumnFull('bar', 'longtext', null, true, '', null, '', 'select,insert,references', ''), ]; $resultStub = $this->createMock(DummyResult::class); @@ -2643,36 +2631,9 @@ class InsertEditTest extends AbstractTestCase // insert $tableColumns = [ - [ - 'Field' => 'foo', - 'Type' => 'longtext', - 'Extra' => '', - 'Null' => 'Yes', - 'Key' => '', - 'pma_type' => 'longtext', - 'True_Type' => 'longtext', - 'Privileges' => 'select,insert,update,references', - ], - [ - 'Field' => 'bar', - 'Type' => 'longtext', - 'Extra' => '', - 'Null' => 'Yes', - 'Key' => '', - 'pma_type' => 'longtext', - 'True_Type' => 'longtext', - 'Privileges' => 'select,update,references', - ], - [ - 'Field' => 'point', - 'Type' => 'point', - 'Extra' => '', - 'Null' => 'No', - 'Key' => '', - 'pma_type' => 'point', - 'True_Type' => 'point', - 'Privileges' => 'select,update,references', - ], + new ColumnFull('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''), + new ColumnFull('bar', 'longtext', null, true, '', null, '', 'select,update,references', ''), + new ColumnFull('point', 'point', null, false, '', null, '', 'select,update,references', ''), ]; $actual = $this->insertEdit->getHtmlForInsertEditRow( [], From 2c9153ac5d9702ddfa728ed9e60dcfcd0013649d Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 00:33:14 +0100 Subject: [PATCH 3/9] Refactor column length calculation Signed-off-by: Kamil Tekiela --- libraries/classes/InsertEdit.php | 63 ++++++++++++++++---------------- test/classes/InsertEditTest.php | 11 ++---- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 531275d775..8eee7a5cf8 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -303,14 +303,16 @@ class InsertEdit /** * Analyze the table column array * - * @param ColumnFull $tableColumn description of column in given table - * @param string[] $commentsMap comments for every column that has a comment + * @param ColumnFull $tableColumn description of column in given table + * @param string[] $commentsMap comments for every column that has a comment + * @param int $columnLength length of the current column taken from field metadata * * @return mixed[] description of column in given table */ private function analyzeTableColumnsArray( ColumnFull $tableColumn, array $commentsMap, + int $columnLength, ): array { $column = [ 'Field' => $tableColumn->field, @@ -326,7 +328,13 @@ class InsertEdit $column['Field_md5'] = md5($tableColumn->field); // True_Type contains only the type (stops at first bracket) $column['True_Type'] = preg_replace('@\(.*@s', '', $tableColumn->type); - $column['len'] = preg_match('@float|double@', $tableColumn->type) ? 100 : -1; + $column['len'] = preg_match('@float|double@', $tableColumn->type) ? 100 : $columnLength; + // length is unknown for geometry fields, + // make enough space to edit very simple WKTs + if ($column['len'] === -1) { + $column['len'] = 30; + } + $column['Field_title'] = $this->getColumnTitle($tableColumn->field, $commentsMap); $column['is_binary'] = $this->isColumn( $tableColumn->type, @@ -1680,29 +1688,29 @@ class InsertEdit /** * Function to get html for each insert/edit column * - * @param ColumnFull $tableColumn column - * @param int $columnNumber column index in table_columns - * @param string[] $commentsMap comments map - * @param ResultInterface $currentResult current result - * @param bool $insertMode whether insert mode - * @param mixed[] $currentRow current row - * @param int $columnsCnt columns count - * @param bool $isUpload whether upload - * @param mixed[] $foreigners foreigners - * @param string $table table - * @param string $db database - * @param int $rowId row id - * @param string $defaultCharEditing default char editing mode which is stored in the config.inc.php script - * @param string $textDir text direction - * @param mixed[] $repopulate the data to be repopulated - * @param mixed[] $columnMime the mime information of column - * @param string $whereClause the where clause + * @param ColumnFull $tableColumn column + * @param int $columnNumber column index in table_columns + * @param string[] $commentsMap comments map + * @param int $columnLength length of the current column taken from field metadata + * @param bool $insertMode whether insert mode + * @param mixed[] $currentRow current row + * @param int $columnsCnt columns count + * @param bool $isUpload whether upload + * @param mixed[] $foreigners foreigners + * @param string $table table + * @param string $db database + * @param int $rowId row id + * @param string $defaultCharEditing default char editing mode which is stored in the config.inc.php script + * @param string $textDir text direction + * @param mixed[] $repopulate the data to be repopulated + * @param mixed[] $columnMime the mime information of column + * @param string $whereClause the where clause */ private function getHtmlForInsertEditFormColumn( ColumnFull $tableColumn, int $columnNumber, array $commentsMap, - ResultInterface $currentResult, + int $columnLength, bool $insertMode, array $currentRow, int $columnsCnt, @@ -1717,7 +1725,7 @@ class InsertEdit array $columnMime, string $whereClause, ): string { - $column = $this->analyzeTableColumnsArray($tableColumn, $commentsMap); + $column = $this->analyzeTableColumnsArray($tableColumn, $commentsMap, $columnLength); $asIs = false; /** @var string $fieldHashMd5 */ @@ -1729,15 +1737,6 @@ class InsertEdit $extractedColumnspec = Util::extractColumnSpec($column['Type']); - if ($column['len'] === -1) { - $column['len'] = $this->dbi->getFieldsMeta($currentResult)[$columnNumber]->length; - // length is unknown for geometry fields, - // make enough space to edit very simple WKTs - if ($column['len'] === -1) { - $column['len'] = 30; - } - } - //Call validation when the form submitted... $onChangeClause = 'return verificationsAfterFieldChange(' . json_encode($fieldHashMd5) . ', ' @@ -2080,7 +2079,7 @@ class InsertEdit $tableColumn, $columnNumber, $commentsMap, - $currentResult, + $this->dbi->getFieldsMeta($currentResult)[$columnNumber]->length, $insertMode, $currentRow, $columnCount, diff --git a/test/classes/InsertEditTest.php b/test/classes/InsertEditTest.php index af6ae0a915..cc98022bc9 100644 --- a/test/classes/InsertEditTest.php +++ b/test/classes/InsertEditTest.php @@ -420,7 +420,7 @@ class InsertEditTest extends AbstractTestCase $this->insertEdit, InsertEdit::class, 'analyzeTableColumnsArray', - [$column, []], + [$column, [], -1], ); $this->assertEquals($result['Field_md5'], '4342210df36bf2ff2c4e2a997a6d4089'); @@ -2411,11 +2411,6 @@ class InsertEditTest extends AbstractTestCase 'input_transformation_options' => '150', ]; - $resultStub = $this->createMock(DummyResult::class); - $resultStub->expects($this->any()) - ->method('getFieldsMeta') - ->will($this->returnValue([FieldHelper::fromArray(['type' => 0, 'length' => -1])])); - // Test w/ input transformation $actual = $this->callFunction( $this->insertEdit, @@ -2425,7 +2420,7 @@ class InsertEditTest extends AbstractTestCase $tableColumn, 0, [], - $resultStub, + -1, false, [], 0, @@ -2470,7 +2465,7 @@ class InsertEditTest extends AbstractTestCase $tableColumn, 0, [], - $resultStub, + -1, true, [], 0, From 0d9e7958902a55627fadb79ca2eeadcf112d84a9 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 00:47:04 +0100 Subject: [PATCH 4/9] Narrow down type of SHOW COLUMNS MySQL clearly defines the structure of the fields for SHOW [FULL] COLUMNS. We can be sure it will be either string or null. Signed-off-by: Kamil Tekiela --- libraries/classes/DatabaseInterface.php | 16 +-- phpstan-baseline.neon | 87 ++++------- psalm-baseline.xml | 183 ++++++++++-------------- 3 files changed, 106 insertions(+), 180 deletions(-) diff --git a/libraries/classes/DatabaseInterface.php b/libraries/classes/DatabaseInterface.php index 36deed9ca0..e01d25fdad 100644 --- a/libraries/classes/DatabaseInterface.php +++ b/libraries/classes/DatabaseInterface.php @@ -839,7 +839,7 @@ class DatabaseInterface implements DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return mixed[] flat array description + * @return (string|null)[] flat array description */ public function getColumn( string $database, @@ -854,7 +854,7 @@ class DatabaseInterface implements DbalInterface $this->escapeString($this->escapeMysqlWildcards($column)), $full, ); - /** @var array $fields */ + /** @var (string|null)[][] $fields */ $fields = $this->fetchResult($sql, 'Field', null, $connectionType); $columns = $this->attachIndexInfoToColumns($database, $table, $fields); @@ -870,7 +870,7 @@ class DatabaseInterface implements DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return mixed[][] array indexed by column names + * @return (string|null)[][] array indexed by column names */ public function getColumns( string $database, @@ -879,7 +879,7 @@ class DatabaseInterface implements DbalInterface int $connectionType = Connection::TYPE_USER, ): array { $sql = QueryGenerator::getColumnsSql($database, $table, null, $full); - /** @var array[] $fields */ + /** @var (string|null)[][] $fields */ $fields = $this->fetchResult($sql, 'Field', null, $connectionType); return $this->attachIndexInfoToColumns($database, $table, $fields); @@ -888,11 +888,11 @@ class DatabaseInterface implements DbalInterface /** * Attach index information to the column definition * - * @param string $database name of database - * @param string $table name of table to retrieve columns from - * @param mixed[][] $fields column array indexed by their names + * @param string $database name of database + * @param string $table name of table to retrieve columns from + * @param (string|null)[][] $fields column array indexed by their names * - * @return mixed[][] Column defintions with index information + * @return (string|null)[][] Column defintions with index information */ private function attachIndexInfoToColumns( string $database, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ba99b96288..47ebf97bd2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -656,7 +656,7 @@ parameters: path: libraries/classes/ConfigStorage/Relation.php - - message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getComments\\(\\) should return array\\ but returns array\\\\.$#" + message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getComments\\(\\) should return array\\ but returns array\\\\.$#" count: 1 path: libraries/classes/ConfigStorage/Relation.php @@ -776,7 +776,7 @@ parameters: path: libraries/classes/Controllers/Database/CentralColumnsController.php - - message: "#^Cannot access offset mixed on mixed\\.$#" + message: "#^Cannot access offset string\\|null on mixed\\.$#" count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php @@ -786,12 +786,12 @@ parameters: path: libraries/classes/Controllers/Database/DataDictionaryController.php - - message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php - - message: "#^Parameter \\#2 \\$column of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:searchColumnInForeigners\\(\\) expects string, mixed given\\.$#" + message: "#^Parameter \\#2 \\$column of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:searchColumnInForeigners\\(\\) expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php @@ -2095,11 +2095,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/FindReplaceController.php - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/FindReplaceController.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 16 @@ -2171,12 +2166,7 @@ parameters: path: libraries/classes/Controllers/Table/RelationController.php - - message: "#^Parameter \\#1 \\$string of function md5 expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/RelationController.php - - - - message: "#^Parameter \\#2 \\$callback of function uksort expects callable\\(int\\|string, int\\|string\\)\\: int, 'strnatcasecmp' given\\.$#" + message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/Controllers/Table/RelationController.php @@ -2222,7 +2212,7 @@ parameters: - message: "#^Cannot cast mixed to string\\.$#" - count: 2 + count: 1 path: libraries/classes/Controllers/Table/SearchController.php - @@ -2527,7 +2517,7 @@ parameters: - message: "#^Cannot cast mixed to string\\.$#" - count: 3 + count: 2 path: libraries/classes/Controllers/Table/ZoomSearchController.php - @@ -2742,7 +2732,7 @@ parameters: - message: "#^Cannot cast mixed to string\\.$#" - count: 4 + count: 3 path: libraries/classes/Database/CentralColumns.php - @@ -2782,7 +2772,12 @@ parameters: - message: "#^Parameter \\#1 \\$str of method PhpMyAdmin\\\\DatabaseInterface\\:\\:escapeString\\(\\) expects string, mixed given\\.$#" - count: 6 + count: 5 + path: libraries/classes/Database/CentralColumns.php + + - + message: "#^Parameter \\#1 \\$str of method PhpMyAdmin\\\\DatabaseInterface\\:\\:escapeString\\(\\) expects string, string\\|null given\\.$#" + count: 1 path: libraries/classes/Database/CentralColumns.php - @@ -3145,11 +3140,6 @@ parameters: count: 1 path: libraries/classes/Database/Routines.php - - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" - count: 1 - path: libraries/classes/Database/Search.php - - message: "#^Property PhpMyAdmin\\\\Database\\\\Search\\:\\:\\$searchTypeDescription \\(string\\) does not accept mixed\\.$#" count: 1 @@ -3350,11 +3340,6 @@ parameters: count: 1 path: libraries/classes/DatabaseInterface.php - - - message: "#^PHPDoc tag @var for variable \\$fields has no value type specified in iterable type array\\.$#" - count: 2 - path: libraries/classes/DatabaseInterface.php - - message: "#^Parameter \\#1 \\$a of static method PhpMyAdmin\\\\Query\\\\Utilities\\:\\:usortComparisonCallback\\(\\) expects array, mixed given\\.$#" count: 1 @@ -4626,7 +4611,7 @@ parameters: path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#1 \\$field of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$field of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php @@ -4711,12 +4696,7 @@ parameters: path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#2 \\$type of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#3 \\$collation of class PhpMyAdmin\\\\ColumnFull constructor expects string\\|null, mixed given\\.$#" + message: "#^Parameter \\#2 \\$type of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php @@ -4726,27 +4706,22 @@ parameters: path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#5 \\$key of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#5 \\$key of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#6 \\$default of class PhpMyAdmin\\\\ColumnFull constructor expects string\\|null, mixed given\\.$#" + message: "#^Parameter \\#7 \\$extra of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#7 \\$extra of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#8 \\$privileges of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#8 \\$privileges of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#9 \\$comment of class PhpMyAdmin\\\\ColumnFull constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#9 \\$comment of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/InsertEdit.php @@ -4985,11 +4960,6 @@ parameters: count: 2 path: libraries/classes/Normalization.php - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: libraries/classes/Normalization.php - - message: "#^Casting to string something that's already string\\.$#" count: 1 @@ -5015,11 +4985,6 @@ parameters: count: 1 path: libraries/classes/Normalization.php - - - message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, mixed given\\.$#" - count: 1 - path: libraries/classes/Normalization.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, \\(int\\|string\\) given\\.$#" count: 3 @@ -5040,6 +5005,11 @@ parameters: count: 2 path: libraries/classes/Normalization.php + - + message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#" + count: 2 + path: libraries/classes/Normalization.php + - message: "#^Parameter \\#1 \\$string of function mb_strtoupper expects string, mixed given\\.$#" count: 1 @@ -7921,7 +7891,7 @@ parameters: path: libraries/classes/Sql.php - - message: "#^Parameter \\#1 \\$haystack of function str_contains expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$haystack of function str_contains expects string, string\\|null given\\.$#" count: 1 path: libraries/classes/Sql.php @@ -9115,11 +9085,6 @@ parameters: count: 2 path: test/classes/Controllers/Table/ReplaceControllerTest.php - - - message: "#^Cannot cast mixed to string\\.$#" - count: 3 - path: test/classes/Controllers/Table/StructureControllerTest.php - - message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsArray\\(\\) with array\\ will always evaluate to true\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index d765275bac..92657d4ffe 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -686,10 +686,12 @@ + $comments $tableNameReplacements ]]> + string[] - $foreign[$field] $foreign[$field] $foreign[$key] @@ -754,7 +755,6 @@ $childReferences $column $columns - $field $foreignDb $foreignField @@ -784,10 +784,6 @@ $foreigners[$column] - - $comments - string[] - $foreigners + + $comments + getDbComments @@ -963,17 +962,6 @@ - - - - - - - - - - - $relation @@ -981,6 +969,15 @@ $relation + + + + + + $columnsComments + $mimeMap + $rows + __construct @@ -3667,7 +3664,6 @@ - $foreignDb $foreignTable $html @@ -3677,20 +3673,14 @@ : []]]> - - - - - - $existrelForeign $foreignDb $foreignTable @@ -3720,6 +3710,13 @@ $foreignTable $foreignTable + + + + + $columnArray + $columnHashArray + @@ -5542,9 +5539,6 @@ tablesNamesOnly)]]> - - - searchTypeDescription]]> @@ -7630,16 +7624,9 @@ - - - - - - - @@ -7650,7 +7637,6 @@ - @@ -7797,6 +7783,14 @@ + + + + + + + + @@ -8253,9 +8247,6 @@ $col - - - $dependent $dependents $dependents @@ -8320,10 +8311,6 @@ - - - - (string) $dependon @@ -8945,7 +8932,6 @@ $comments[$fieldName] - $fieldName @@ -8961,21 +8947,12 @@ - - - - $comments[$fieldName] - $mimeMap[$fieldName] - $colAlias $colAs $colAs $colAs - $colAs - $colAs - $fieldName $trigger $value @@ -8991,12 +8968,19 @@ $value + $colAs + $colAs + $fieldName $tableAlias $tableAlias $tableAlias $tableAlias $tableAlias + + $comments + $mimeMap + $comments $mimeMap @@ -9024,29 +9008,21 @@ $columnsAlias[$i] $escape[$k] - $fieldName - - - - - $colAs $colAs $colAs $columnsAlias[$i] - $fieldName $type $colAs $comments[$fieldName] $escape[$k] - $type @@ -9064,7 +9040,9 @@ + $fieldName $record[$columns[$i]] + @@ -9082,21 +9060,13 @@ - - - - $colAs $colAs $column $colAs $column - - - - $doComments @@ -9104,6 +9074,10 @@ $doRelation + + + + $row[$i] $tableAlias $tableAlias @@ -9155,7 +9129,6 @@ $comments[$fieldName] - $fieldName @@ -9173,8 +9146,6 @@ - - @@ -9182,9 +9153,6 @@ $colAs $colAs $colAs - $colAs - $colAs - $fieldName $rfield $rfield $rtable @@ -9211,6 +9179,8 @@ $colAs + $colAs + $fieldName $row[$j] $tableAlias $tableAlias @@ -9308,9 +9278,6 @@ $colAlias $colAlias $colAs - - - $engine $eventName $eventName @@ -9346,7 +9313,6 @@ - @@ -9359,7 +9325,6 @@ $colAlias $colAlias - $colAlias $colAs $columnAliases $definition @@ -9381,8 +9346,6 @@ $trigger - - entityOptions->has('AUTO_INCREMENT')]]> @@ -9403,6 +9366,7 @@ Context::escape($alias) + $createQuery $definition name]]> @@ -9419,6 +9383,7 @@ + $eventDef @@ -9464,7 +9429,6 @@ $comments[$fieldName] - $fieldName $type @@ -9479,21 +9443,12 @@ - - - - $comments[$fieldName] - $mimeMap[$fieldName] - $colAlias $colAs $colAs $colAs - $colAs - $colAs - $fieldName $trigger $type $value @@ -9515,7 +9470,13 @@ $colAs + $colAs + $fieldName + + $comments + $mimeMap + $tableAlias $tableAlias @@ -9603,7 +9564,6 @@ tMargin]]> $cellFontSize $colAs - $fullwidth + $l $fullwidth + $l $fullwidth + $l @@ -9702,10 +9662,6 @@ - $comments[$fieldName] - $mimeMap[$fieldName] - $resRel[$fieldName] - $resRel[$fieldName] headerset[$this->page]]]> headerset[$this->page]]]> pagedim[$oldpage]]]> @@ -9733,9 +9689,6 @@ $data[] $data[] $data[] - $data[] - $data[] - $fieldName $fullwidth $fullwidth $fullwidth @@ -9866,9 +9819,16 @@ $topMargin + $row[$key] $txt + + $comments + $mimeMap + $resRel + $resRel + @@ -10769,15 +10729,12 @@ diagram->PageNo()]]> - $fieldName - $fieldName $oneField - @@ -10829,19 +10786,14 @@ diagram->customLinks['RT'][$table]]]> - diagram->customLinks['RT'][$table][$fieldName]]]> diagram->customLinks['doc'][$foreigner['foreign_table']]]]> diagram->customLinks['doc'][$foreigner['foreign_table']]]]> diagram->customLinks['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']]]]> diagram->customLinks['doc'][$table]]]> diagram->customLinks['doc'][$table]]]> - diagram->customLinks['doc'][$table][$fieldName]]]> - diagram->customLinks['doc'][$table][$fieldName]]]> $attribute - $fieldName - $fieldName $foreignTable $index $links[0] @@ -10873,6 +10825,16 @@ + + $fieldName + $fieldName + + + + diagram->customLinks['RT'][$table]]]> + diagram->customLinks['doc'][$table]]]> + diagram->customLinks['doc'][$table]]]> + @@ -11590,8 +11552,6 @@ $errorMessage $serverReplicationVariable $successMessage - - @@ -11636,6 +11596,8 @@ $srReplicaAction + + strtok @@ -12328,7 +12290,6 @@ - @@ -12433,6 +12394,7 @@ altered[0]->field->column]]> + $result $row[0] parser->list]]> @@ -13371,7 +13333,6 @@ $array $columnNames[] - $columnNames[] From 0aa3210ee10be006cd6ac4f8d7545329f7c5929d Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 00:56:13 +0100 Subject: [PATCH 5/9] Use array shape instead of (string|null)[] Signed-off-by: Kamil Tekiela --- libraries/classes/DatabaseInterface.php | 24 +++- libraries/classes/Dbal/DbalInterface.php | 24 +++- phpstan-baseline.neon | 131 +++++++++---------- psalm-baseline.xml | 154 ++++++++++++----------- 4 files changed, 190 insertions(+), 143 deletions(-) diff --git a/libraries/classes/DatabaseInterface.php b/libraries/classes/DatabaseInterface.php index e01d25fdad..7de3237a35 100644 --- a/libraries/classes/DatabaseInterface.php +++ b/libraries/classes/DatabaseInterface.php @@ -839,7 +839,17 @@ class DatabaseInterface implements DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return (string|null)[] flat array description + * @return array{ + * Field: string, + * Type: string, + * Collation?: string|null, + * Null:'YES'|'NO', + * Key: string, + * Default: string|null, + * Extra: string, + * Privileges?: string, + * Comment?: string + * } */ public function getColumn( string $database, @@ -870,7 +880,17 @@ class DatabaseInterface implements DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return (string|null)[][] array indexed by column names + * @return array{ + * Field: string, + * Type: string, + * Collation?: string|null, + * Null:'YES'|'NO', + * Key: string, + * Default: string|null, + * Extra: string, + * Privileges?: string, + * Comment?: string + * }[] array indexed by column names */ public function getColumns( string $database, diff --git a/libraries/classes/Dbal/DbalInterface.php b/libraries/classes/Dbal/DbalInterface.php index 21082e13dd..7406f49304 100644 --- a/libraries/classes/Dbal/DbalInterface.php +++ b/libraries/classes/Dbal/DbalInterface.php @@ -173,7 +173,17 @@ interface DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return mixed[] flat array description + * @return array{ + * Field: string, + * Type: string, + * Collation?: string|null, + * Null:'YES'|'NO', + * Key: string, + * Default: string|null, + * Extra: string, + * Privileges?: string, + * Comment?: string + * } */ public function getColumn( string $database, @@ -191,7 +201,17 @@ interface DbalInterface * @param bool $full whether to return full info or only column names * @psalm-param ConnectionType $connectionType * - * @return mixed[][] array indexed by column names + * @return array{ + * Field: string, + * Type: string, + * Collation?: string|null, + * Null:'YES'|'NO', + * Key: string, + * Default: string|null, + * Extra: string, + * Privileges?: string, + * Comment?: string + * }[] array indexed by column names */ public function getColumns( string $database, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 47ebf97bd2..de883a2e82 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -655,11 +655,6 @@ parameters: count: 1 path: libraries/classes/ConfigStorage/Relation.php - - - message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getComments\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: libraries/classes/ConfigStorage/Relation.php - - message: "#^Method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:getDisplayField\\(\\) should return string but returns mixed\\.$#" count: 1 @@ -690,6 +685,11 @@ parameters: count: 1 path: libraries/classes/ConfigStorage/Relation.php + - + message: "#^Offset 'Comment' does not exist on array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\}\\.$#" + count: 1 + path: libraries/classes/ConfigStorage/Relation.php + - message: "#^Parameter \\#1 \\$foreigners of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:searchColumnInForeigners\\(\\) expects array, array\\|true given\\.$#" count: 1 @@ -776,7 +776,7 @@ parameters: path: libraries/classes/Controllers/Database/CentralColumnsController.php - - message: "#^Cannot access offset string\\|null on mixed\\.$#" + message: "#^Cannot access offset string on mixed\\.$#" count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php @@ -786,12 +786,7 @@ parameters: path: libraries/classes/Controllers/Database/DataDictionaryController.php - - message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/Controllers/Database/DataDictionaryController.php - - - - message: "#^Parameter \\#2 \\$column of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:searchColumnInForeigners\\(\\) expects string, string\\|null given\\.$#" + message: "#^Strict comparison using \\!\\=\\= between 'NO'\\|'YES' and '' will always evaluate to true\\.$#" count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php @@ -2095,6 +2090,11 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/FindReplaceController.php + - + message: "#^Casting to string something that's already string\\.$#" + count: 1 + path: libraries/classes/Controllers/Table/FindReplaceController.php + - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 16 @@ -2165,11 +2165,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/RelationController.php - - - message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/RelationController.php - - message: "#^Parameter \\#2 \\$callback of function usort expects callable\\(mixed, mixed\\)\\: int, 'strnatcasecmp' given\\.$#" count: 1 @@ -2215,6 +2210,11 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SearchController.php + - + message: "#^Casting to string something that's already string\\.$#" + count: 1 + path: libraries/classes/Controllers/Table/SearchController.php + - message: "#^Method PhpMyAdmin\\\\Controllers\\\\Table\\\\SearchController\\:\\:getColumnMinMax\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -2285,6 +2285,11 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/Structure/ChangeController.php + - + message: "#^Strict comparison using \\=\\=\\= between array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\} and array\\{\\} will always evaluate to false\\.$#" + count: 1 + path: libraries/classes/Controllers/Table/Structure/ChangeController.php + - message: "#^Cannot access offset 'COLUMN_COMMENT' on mixed\\.$#" count: 1 @@ -2520,6 +2525,11 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/ZoomSearchController.php + - + message: "#^Casting to string something that's already string\\.$#" + count: 1 + path: libraries/classes/Controllers/Table/ZoomSearchController.php + - message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, mixed given\\.$#" count: 1 @@ -2735,6 +2745,11 @@ parameters: count: 3 path: libraries/classes/Database/CentralColumns.php + - + message: "#^Casting to string something that's already string\\.$#" + count: 1 + path: libraries/classes/Database/CentralColumns.php + - message: "#^Foreach overwrites \\$table with its value variable\\.$#" count: 2 @@ -2775,11 +2790,6 @@ parameters: count: 5 path: libraries/classes/Database/CentralColumns.php - - - message: "#^Parameter \\#1 \\$str of method PhpMyAdmin\\\\DatabaseInterface\\:\\:escapeString\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/Database/CentralColumns.php - - message: "#^Parameter \\#1 \\$string of function bin2hex expects string, mixed given\\.$#" count: 2 @@ -3315,11 +3325,21 @@ parameters: count: 1 path: libraries/classes/DatabaseInterface.php + - + message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumn\\(\\) should return array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\} but returns array\\\\.$#" + count: 1 + path: libraries/classes/DatabaseInterface.php + - message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumnNames\\(\\) should return array\\ but returns array\\.$#" count: 1 path: libraries/classes/DatabaseInterface.php + - + message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumns\\(\\) should return array\\ but returns array\\\\>\\.$#" + count: 1 + path: libraries/classes/DatabaseInterface.php + - message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumnsFull\\(\\) should return array but returns mixed\\.$#" count: 1 @@ -4595,6 +4615,21 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php + - + message: "#^Offset 'Collation' does not exist on array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\}\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Offset 'Comment' does not exist on array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\}\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + + - + message: "#^Offset 'Privileges' does not exist on array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\}\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + - message: "#^Parameter \\#1 \\$buffer of method PhpMyAdmin\\\\Plugins\\\\TransformationsPlugin\\:\\:applyTransformation\\(\\) expects string, mixed given\\.$#" count: 1 @@ -4610,11 +4645,6 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php - - - message: "#^Parameter \\#1 \\$field of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#1 \\$haystack of function mb_strstr expects string, mixed given\\.$#" count: 2 @@ -4695,36 +4725,11 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php - - - message: "#^Parameter \\#2 \\$type of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - message: "#^Parameter \\#3 \\$row of static method PhpMyAdmin\\\\Util\\:\\:getUniqueCondition\\(\\) expects array\\, mixed given\\.$#" count: 1 path: libraries/classes/InsertEdit.php - - - message: "#^Parameter \\#5 \\$key of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#7 \\$extra of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#8 \\$privileges of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - - - message: "#^Parameter \\#9 \\$comment of class PhpMyAdmin\\\\ColumnFull constructor expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/InsertEdit.php - - message: "#^Binary operation \"\\-\" between string and 1 results in an error\\.$#" count: 1 @@ -4962,7 +4967,7 @@ parameters: - message: "#^Casting to string something that's already string\\.$#" - count: 1 + count: 2 path: libraries/classes/Normalization.php - @@ -4980,6 +4985,11 @@ parameters: count: 1 path: libraries/classes/Normalization.php + - + message: "#^Offset 'Type' on array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\} in isset\\(\\) always exists and is not nullable\\.$#" + count: 1 + path: libraries/classes/Normalization.php + - message: "#^Parameter \\#1 \\$array of function array_unique expects array, mixed given\\.$#" count: 1 @@ -5005,11 +5015,6 @@ parameters: count: 2 path: libraries/classes/Normalization.php - - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#" - count: 2 - path: libraries/classes/Normalization.php - - message: "#^Parameter \\#1 \\$string of function mb_strtoupper expects string, mixed given\\.$#" count: 1 @@ -7890,11 +7895,6 @@ parameters: count: 1 path: libraries/classes/Sql.php - - - message: "#^Parameter \\#1 \\$haystack of function str_contains expects string, string\\|null given\\.$#" - count: 1 - path: libraries/classes/Sql.php - - message: "#^Parameter \\#1 \\$message of static method PhpMyAdmin\\\\Message\\:\\:rawError\\(\\) expects string, mixed given\\.$#" count: 1 @@ -9085,6 +9085,11 @@ parameters: count: 2 path: test/classes/Controllers/Table/ReplaceControllerTest.php + - + message: "#^Casting to string something that's already string\\.$#" + count: 3 + path: test/classes/Controllers/Table/StructureControllerTest.php + - message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsArray\\(\\) with array\\ will always evaluate to true\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 92657d4ffe..b59706e500 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -686,12 +686,10 @@ - $comments $tableNameReplacements ]]> - string[] $foreigners - - $comments - + + + + getDbComments @@ -962,6 +961,9 @@ + + + $relation @@ -969,21 +971,15 @@ $relation - - - - - - $columnsComments - $mimeMap - $rows - __construct $request + + + @@ -3462,6 +3458,9 @@ $request + + + @@ -3710,13 +3709,6 @@ $foreignTable $foreignTable - - - - - $columnArray - $columnHashArray - @@ -3876,6 +3868,9 @@ $request + + + @@ -3949,6 +3944,10 @@ + + $value === [] + $value === [] + @@ -4324,6 +4323,9 @@ $request + + + @@ -4767,7 +4769,6 @@ $default - $field $key @@ -4859,7 +4860,6 @@ $defaultValue $defaultValues[$rowNum] $extra - $field $hasList[] $key $length @@ -4918,6 +4918,9 @@ + + + @@ -5769,6 +5772,7 @@ reset($columns) + attachIndexInfoToColumns($database, $table, $fields)]]> fetchResult($sql, null, 'Field', $connectionType)]]> fetchResult($sql, null, null, $connectionType)]]> ]]> + array_shift($columns) ?? [] + + string[] @@ -7783,15 +7810,10 @@ - - - - - - - - + + + @@ -8314,6 +8336,9 @@ (string) $dependon + + + @@ -8968,19 +8993,12 @@ $value - $colAs - $colAs - $fieldName $tableAlias $tableAlias $tableAlias $tableAlias $tableAlias - - $comments - $mimeMap - $comments $mimeMap @@ -8999,6 +9017,10 @@ + + + + @@ -9040,9 +9062,7 @@ - $fieldName $record[$columns[$i]] - @@ -9075,9 +9095,6 @@ - - - $row[$i] $tableAlias $tableAlias @@ -9179,8 +9196,6 @@ $colAs - $colAs - $fieldName $row[$j] $tableAlias $tableAlias @@ -9366,7 +9381,6 @@ Context::escape($alias) - $createQuery $definition name]]> @@ -9383,7 +9397,6 @@ - $eventDef @@ -9470,13 +9483,7 @@ $colAs - $colAs - $fieldName - - $comments - $mimeMap - $tableAlias $tableAlias @@ -9557,6 +9564,10 @@ + + + + @@ -9819,16 +9830,9 @@ $topMargin - $row[$key] $txt - - $comments - $mimeMap - $resRel - $resRel - @@ -10724,6 +10728,10 @@ + + + + diagram->PageNo()]]> diagram->PageNo()]]> @@ -10825,22 +10833,12 @@ - - $fieldName - $fieldName - - - - diagram->customLinks['RT'][$table]]]> - diagram->customLinks['doc'][$table]]]> - diagram->customLinks['doc'][$table]]]> - - - - isWithDataDictionary + + + $bottomMargin $rightMargin @@ -11596,8 +11594,6 @@ $srReplicaAction - - strtok @@ -12394,7 +12390,6 @@ altered[0]->field->column]]> - $result $row[0] parser->list]]> @@ -13961,6 +13956,13 @@ expects + + + + + + + testPopulateRequestWithEncryptedQueryParamsWithInvalidParam From fccaaf65a390d5ccbfaf6e312562871a3ee425b2 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 01:05:53 +0100 Subject: [PATCH 6/9] Remove all new Psalm issues Signed-off-by: Kamil Tekiela --- .../Database/DataDictionaryController.php | 2 +- .../Table/FindReplaceController.php | 2 +- .../Controllers/Table/SearchController.php | 2 +- .../Table/ZoomSearchController.php | 2 +- libraries/classes/Database/CentralColumns.php | 2 +- libraries/classes/Normalization.php | 2 +- .../classes/Plugins/Export/ExportLatex.php | 3 +- .../classes/Plugins/Export/Helpers/Pdf.php | 2 +- .../Plugins/Schema/Pdf/PdfRelationSchema.php | 4 +- phpstan-baseline.neon | 32 +------------- psalm-baseline.xml | 43 ------------------- .../Table/StructureControllerTest.php | 6 +-- 12 files changed, 14 insertions(+), 88 deletions(-) diff --git a/libraries/classes/Controllers/Database/DataDictionaryController.php b/libraries/classes/Controllers/Database/DataDictionaryController.php index 322d0b0e95..8588a7e1e7 100644 --- a/libraries/classes/Controllers/Database/DataDictionaryController.php +++ b/libraries/classes/Controllers/Database/DataDictionaryController.php @@ -84,7 +84,7 @@ class DataDictionaryController extends AbstractController 'has_primary_key' => isset($primaryKeys[$row['Field']]), 'type' => $extractedColumnSpec['type'], 'print_type' => $extractedColumnSpec['print_type'], - 'is_nullable' => $row['Null'] !== '' && $row['Null'] !== 'NO', + 'is_nullable' => $row['Null'] !== 'NO', 'default' => $row['Default'] ?? null, 'comment' => $columnsComments[$row['Field']] ?? '', 'mime' => $mime, diff --git a/libraries/classes/Controllers/Table/FindReplaceController.php b/libraries/classes/Controllers/Table/FindReplaceController.php index 9e639cbba8..d67c61c586 100644 --- a/libraries/classes/Controllers/Table/FindReplaceController.php +++ b/libraries/classes/Controllers/Table/FindReplaceController.php @@ -91,7 +91,7 @@ class FindReplaceController extends AbstractController // set column name $this->columnNames[] = $row['Field']; - $type = (string) $row['Type']; + $type = $row['Type']; // reformat mysql query output if (strncasecmp($type, 'set', 3) == 0 || strncasecmp($type, 'enum', 4) == 0) { $type = str_replace(',', ', ', $type); diff --git a/libraries/classes/Controllers/Table/SearchController.php b/libraries/classes/Controllers/Table/SearchController.php index 763544ac95..37fb6fd7ab 100644 --- a/libraries/classes/Controllers/Table/SearchController.php +++ b/libraries/classes/Controllers/Table/SearchController.php @@ -109,7 +109,7 @@ class SearchController extends AbstractController // set column name $this->columnNames[] = $row['Field']; - $type = (string) $row['Type']; + $type = $row['Type']; // before any replacement $this->originalColumnTypes[] = mb_strtolower($type); // check whether table contains geometric columns diff --git a/libraries/classes/Controllers/Table/ZoomSearchController.php b/libraries/classes/Controllers/Table/ZoomSearchController.php index a9a37036a4..375ba4a977 100644 --- a/libraries/classes/Controllers/Table/ZoomSearchController.php +++ b/libraries/classes/Controllers/Table/ZoomSearchController.php @@ -165,7 +165,7 @@ class ZoomSearchController extends AbstractController // set column name $this->columnNames[] = $row['Field']; - $type = (string) $row['Type']; + $type = $row['Type']; // before any replacement $this->originalColumnTypes[] = mb_strtolower($type); // check whether table contains geometric columns diff --git a/libraries/classes/Database/CentralColumns.php b/libraries/classes/Database/CentralColumns.php index 8f53e0a89e..3de1dd9d92 100644 --- a/libraries/classes/Database/CentralColumns.php +++ b/libraries/classes/Database/CentralColumns.php @@ -293,7 +293,7 @@ class CentralColumns $hasList = $this->findExistingColNames($db, trim($cols, ',')); foreach ($fieldSelect as $table) { foreach ($fields[$table] as $def) { - $field = (string) $def['Field']; + $field = $def['Field']; if (! in_array($field, $hasList)) { $hasList[] = $field; $insQuery[] = $this->getInsertQuery($field, $def, $db, $centralListTable); diff --git a/libraries/classes/Normalization.php b/libraries/classes/Normalization.php index 14b4674a34..c6b4011ebb 100644 --- a/libraries/classes/Normalization.php +++ b/libraries/classes/Normalization.php @@ -72,7 +72,7 @@ class Normalization $type = ''; $selectColHtml = ''; foreach ($columns as $def) { - $column = (string) $def['Field']; + $column = $def['Field']; if (isset($def['Type'])) { $extractedColumnSpec = Util::extractColumnSpec($def['Type']); $type = $extractedColumnSpec['type']; diff --git a/libraries/classes/Plugins/Export/ExportLatex.php b/libraries/classes/Plugins/Export/ExportLatex.php index bddaf7fb3c..0dc867edfa 100644 --- a/libraries/classes/Plugins/Export/ExportLatex.php +++ b/libraries/classes/Plugins/Export/ExportLatex.php @@ -574,8 +574,7 @@ class ExportLatex extends ExportPlugin } $localBuffer = $colAs . "\000" . $type . "\000" - . ($row['Null'] == '' || $row['Null'] === 'NO' - ? __('No') : __('Yes')) + . ($row['Null'] === 'NO' ? __('No') : __('Yes')) . "\000" . ($row['Default'] ?? ''); if ($doRelation && $haveRel) { diff --git a/libraries/classes/Plugins/Export/Helpers/Pdf.php b/libraries/classes/Plugins/Export/Helpers/Pdf.php index 3f8dad6824..d12b2a7e2d 100644 --- a/libraries/classes/Plugins/Export/Helpers/Pdf.php +++ b/libraries/classes/Plugins/Export/Helpers/Pdf.php @@ -568,7 +568,7 @@ class Pdf extends PdfLib $data[] = $column['Field']; $data[] = $type; - $data[] = $column['Null'] == '' || $column['Null'] === 'NO' + $data[] = $column['Null'] === 'NO' ? 'No' : 'Yes'; $data[] = $column['Default'] ?? ''; diff --git a/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php b/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php index 98305dda0c..1d2de2b383 100644 --- a/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php +++ b/libraries/classes/Plugins/Schema/Pdf/PdfRelationSchema.php @@ -680,7 +680,7 @@ class PdfRelationSchema extends ExportRelationSchema $type = $extractedColumnSpec['print_type']; $attribute = $extractedColumnSpec['attribute']; if (! isset($row['Default'])) { - if ($row['Null'] != '' && $row['Null'] !== 'NO') { + if ($row['Null'] !== 'NO') { $row['Default'] = 'NULL'; } } @@ -712,7 +712,7 @@ class PdfRelationSchema extends ExportRelationSchema $fieldName, $type, $attribute, - $row['Null'] == '' || $row['Null'] === 'NO' + $row['Null'] === 'NO' ? __('No') : __('Yes'), $row['Default'] ?? '', diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index de883a2e82..97012c43d8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -785,11 +785,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Database/DataDictionaryController.php - - - message: "#^Strict comparison using \\!\\=\\= between 'NO'\\|'YES' and '' will always evaluate to true\\.$#" - count: 1 - path: libraries/classes/Controllers/Database/DataDictionaryController.php - - message: "#^Cannot access offset 'dbName' on mixed\\.$#" count: 2 @@ -2090,11 +2085,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/FindReplaceController.php - - - message: "#^Casting to string something that's already string\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/FindReplaceController.php - - message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#" count: 16 @@ -2210,11 +2200,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/SearchController.php - - - message: "#^Casting to string something that's already string\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/SearchController.php - - message: "#^Method PhpMyAdmin\\\\Controllers\\\\Table\\\\SearchController\\:\\:getColumnMinMax\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -2525,11 +2510,6 @@ parameters: count: 2 path: libraries/classes/Controllers/Table/ZoomSearchController.php - - - message: "#^Casting to string something that's already string\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/ZoomSearchController.php - - message: "#^Parameter \\#1 \\$columnSpecification of static method PhpMyAdmin\\\\Util\\:\\:extractColumnSpec\\(\\) expects string, mixed given\\.$#" count: 1 @@ -2745,11 +2725,6 @@ parameters: count: 3 path: libraries/classes/Database/CentralColumns.php - - - message: "#^Casting to string something that's already string\\.$#" - count: 1 - path: libraries/classes/Database/CentralColumns.php - - message: "#^Foreach overwrites \\$table with its value variable\\.$#" count: 2 @@ -4967,7 +4942,7 @@ parameters: - message: "#^Casting to string something that's already string\\.$#" - count: 2 + count: 1 path: libraries/classes/Normalization.php - @@ -9085,11 +9060,6 @@ parameters: count: 2 path: test/classes/Controllers/Table/ReplaceControllerTest.php - - - message: "#^Casting to string something that's already string\\.$#" - count: 3 - path: test/classes/Controllers/Table/StructureControllerTest.php - - message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsArray\\(\\) with array\\ will always evaluate to true\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index b59706e500..2a351615c0 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -961,9 +961,6 @@ - - - $relation @@ -977,9 +974,6 @@ $request - - - @@ -3458,9 +3452,6 @@ $request - - - @@ -3868,9 +3859,6 @@ $request - - - @@ -4323,9 +4311,6 @@ $request - - - @@ -4918,9 +4903,6 @@ - - - @@ -8336,9 +8318,6 @@ (string) $dependon - - - @@ -9017,10 +8996,6 @@ - - - - @@ -9564,10 +9539,6 @@ - - - - @@ -10728,10 +10699,6 @@ - - - - diagram->PageNo()]]> diagram->PageNo()]]> @@ -10836,9 +10803,6 @@ isWithDataDictionary - - - $bottomMargin $rightMargin @@ -13956,13 +13920,6 @@ expects - - - - - - - testPopulateRequestWithEncryptedQueryParamsWithInvalidParam diff --git a/test/classes/Controllers/Table/StructureControllerTest.php b/test/classes/Controllers/Table/StructureControllerTest.php index 5f12d1bb96..f8f03b8dd8 100644 --- a/test/classes/Controllers/Table/StructureControllerTest.php +++ b/test/classes/Controllers/Table/StructureControllerTest.php @@ -117,9 +117,9 @@ class StructureControllerTest extends AbstractTestCase 'table_stats' => null, 'fields' => $fields, 'extracted_columnspecs' => [ - 1 => Util::extractColumnSpec((string) $fields['id']['Type']), - 2 => Util::extractColumnSpec((string) $fields['name']['Type']), - 3 => Util::extractColumnSpec((string) $fields['datetimefield']['Type']), + 1 => Util::extractColumnSpec($fields['id']['Type']), + 2 => Util::extractColumnSpec($fields['name']['Type']), + 3 => Util::extractColumnSpec($fields['datetimefield']['Type']), ], 'columns_with_index' => [], 'central_list' => [], From 1d180c54825a9443bc5bbfc8eb61fc93815b6005 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 01:15:31 +0100 Subject: [PATCH 7/9] Use null as sentinel value in getColumn Signed-off-by: Kamil Tekiela --- .../Table/Structure/ChangeController.php | 2 +- libraries/classes/DatabaseInterface.php | 6 ++-- libraries/classes/Dbal/DbalInterface.php | 4 +-- phpstan-baseline.neon | 12 +++---- psalm-baseline.xml | 31 +++++++++---------- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/libraries/classes/Controllers/Table/Structure/ChangeController.php b/libraries/classes/Controllers/Table/Structure/ChangeController.php index e9a1a7519a..37aa2f9d06 100644 --- a/libraries/classes/Controllers/Table/Structure/ChangeController.php +++ b/libraries/classes/Controllers/Table/Structure/ChangeController.php @@ -61,7 +61,7 @@ final class ChangeController extends AbstractController $fieldsMeta = []; foreach ($selected as $column) { $value = $this->dbi->getColumn($GLOBALS['db'], $GLOBALS['table'], $column, true); - if ($value === []) { + if ($value === null) { $message = Message::error( __('Failed to get description of column %s!'), ); diff --git a/libraries/classes/DatabaseInterface.php b/libraries/classes/DatabaseInterface.php index 7de3237a35..2f4e81aa80 100644 --- a/libraries/classes/DatabaseInterface.php +++ b/libraries/classes/DatabaseInterface.php @@ -849,7 +849,7 @@ class DatabaseInterface implements DbalInterface * Extra: string, * Privileges?: string, * Comment?: string - * } + * }|null */ public function getColumn( string $database, @@ -857,7 +857,7 @@ class DatabaseInterface implements DbalInterface string $column, bool $full = false, int $connectionType = Connection::TYPE_USER, - ): array { + ): array|null { $sql = QueryGenerator::getColumnsSql( $database, $table, @@ -869,7 +869,7 @@ class DatabaseInterface implements DbalInterface $columns = $this->attachIndexInfoToColumns($database, $table, $fields); - return array_shift($columns) ?? []; + return array_shift($columns); } /** diff --git a/libraries/classes/Dbal/DbalInterface.php b/libraries/classes/Dbal/DbalInterface.php index 7406f49304..e5fceb7472 100644 --- a/libraries/classes/Dbal/DbalInterface.php +++ b/libraries/classes/Dbal/DbalInterface.php @@ -183,7 +183,7 @@ interface DbalInterface * Extra: string, * Privileges?: string, * Comment?: string - * } + * }|null */ public function getColumn( string $database, @@ -191,7 +191,7 @@ interface DbalInterface string $column, bool $full = false, int $connectionType = Connection::TYPE_USER, - ): array; + ): array|null; /** * Returns descriptions of columns in given table diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 97012c43d8..49f5aa5383 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2270,11 +2270,6 @@ parameters: count: 1 path: libraries/classes/Controllers/Table/Structure/ChangeController.php - - - message: "#^Strict comparison using \\=\\=\\= between array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\} and array\\{\\} will always evaluate to false\\.$#" - count: 1 - path: libraries/classes/Controllers/Table/Structure/ChangeController.php - - message: "#^Cannot access offset 'COLUMN_COMMENT' on mixed\\.$#" count: 1 @@ -2785,6 +2780,11 @@ parameters: count: 1 path: libraries/classes/Database/CentralColumns.php + - + message: "#^Parameter \\#2 \\$def of method PhpMyAdmin\\\\Database\\\\CentralColumns\\:\\:getInsertQuery\\(\\) expects array, array\\\\|null given\\.$#" + count: 1 + path: libraries/classes/Database/CentralColumns.php + - message: "#^Parameter \\#2 \\$string of function explode expects string, mixed given\\.$#" count: 1 @@ -3301,7 +3301,7 @@ parameters: path: libraries/classes/DatabaseInterface.php - - message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumn\\(\\) should return array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\} but returns array\\\\.$#" + message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumn\\(\\) should return array\\{Field\\: string, Type\\: string, Collation\\?\\: string\\|null, Null\\: 'NO'\\|'YES', Key\\: string, Default\\: string\\|null, Extra\\: string, Privileges\\?\\: string, \\.\\.\\.\\}\\|null but returns array\\\\|null\\.$#" count: 1 path: libraries/classes/DatabaseInterface.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2a351615c0..4ec5f01f2c 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -3932,10 +3932,6 @@ - - $value === [] - $value === [] - @@ -4899,6 +4895,9 @@ $db $table + + $field + @@ -5775,18 +5774,7 @@ * Visible?: string, * Expression?: string|null * }>]]> - array_shift($columns) ?? [] - + array_shift($columns) + string[] From 43a864b50fce42dd5c5c4260be9de9614ebae0a2 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 14 May 2023 16:16:58 +0100 Subject: [PATCH 8/9] Assign Default inside analyzeTableColumnsArray Signed-off-by: Kamil Tekiela --- libraries/classes/InsertEdit.php | 18 ++++++++++++------ phpstan-baseline.neon | 7 ++++++- test/classes/InsertEditTest.php | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 8eee7a5cf8..818767892a 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -45,7 +45,6 @@ use function stripcslashes; use function stripslashes; use function strlen; use function substr; -use function time; use function trim; use const ENT_COMPAT; @@ -306,6 +305,7 @@ class InsertEdit * @param ColumnFull $tableColumn description of column in given table * @param string[] $commentsMap comments for every column that has a comment * @param int $columnLength length of the current column taken from field metadata + * @param bool $insertMode whether insert mode * * @return mixed[] description of column in given table */ @@ -313,6 +313,7 @@ class InsertEdit ColumnFull $tableColumn, array $commentsMap, int $columnLength, + bool $insertMode, ): array { $column = [ 'Field' => $tableColumn->field, @@ -362,6 +363,15 @@ class InsertEdit // can only occur once per table $column['first_timestamp'] = $column['True_Type'] === 'timestamp'; + if ( + $tableColumn->type === 'datetime' + && ! $tableColumn->isNull + && $tableColumn->default === null + && $insertMode + ) { + $column['Default'] = date('Y-m-d H:i:s'); + } + return $column; } @@ -1725,7 +1735,7 @@ class InsertEdit array $columnMime, string $whereClause, ): string { - $column = $this->analyzeTableColumnsArray($tableColumn, $commentsMap, $columnLength); + $column = $this->analyzeTableColumnsArray($tableColumn, $commentsMap, $columnLength, $insertMode); $asIs = false; /** @var string $fieldHashMd5 */ @@ -1747,10 +1757,6 @@ class InsertEdit // in the name attribute (see bug #1746964 ) $columnNameAppendix = $vkey . '[' . $fieldHashMd5 . ']'; - if ($column['Type'] === 'datetime' && $column['Null'] !== 'YES' && ! isset($column['Default']) && $insertMode) { - $column['Default'] = date('Y-m-d H:i:s', time()); - } - // Get a list of GIS data types. $gisDataTypes = Gis::getDataTypes(); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 49f5aa5383..35b37c3005 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -4577,7 +4577,7 @@ parameters: - message: "#^Cannot cast mixed to string\\.$#" - count: 2 + count: 3 path: libraries/classes/InsertEdit.php - @@ -4620,6 +4620,11 @@ parameters: count: 1 path: libraries/classes/InsertEdit.php + - + message: "#^Parameter \\#1 \\$defaultValue of method PhpMyAdmin\\\\InsertEdit\\:\\:getSpecialCharsForInsertingMode\\(\\) expects string\\|null, mixed given\\.$#" + count: 1 + path: libraries/classes/InsertEdit.php + - message: "#^Parameter \\#1 \\$haystack of function mb_strstr expects string, mixed given\\.$#" count: 2 diff --git a/test/classes/InsertEditTest.php b/test/classes/InsertEditTest.php index cc98022bc9..1b0a211b31 100644 --- a/test/classes/InsertEditTest.php +++ b/test/classes/InsertEditTest.php @@ -420,7 +420,7 @@ class InsertEditTest extends AbstractTestCase $this->insertEdit, InsertEdit::class, 'analyzeTableColumnsArray', - [$column, [], -1], + [$column, [], -1, false], ); $this->assertEquals($result['Field_md5'], '4342210df36bf2ff2c4e2a997a6d4089'); From 56136bb350c701c26719a8bd1316bb252778a73f Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Mon, 15 May 2023 01:29:52 +0100 Subject: [PATCH 9/9] Fix failing test Signed-off-by: Kamil Tekiela --- test/classes/Stubs/DbiDummy.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/classes/Stubs/DbiDummy.php b/test/classes/Stubs/DbiDummy.php index f7aa0ed294..d0555cbec3 100644 --- a/test/classes/Stubs/DbiDummy.php +++ b/test/classes/Stubs/DbiDummy.php @@ -1643,11 +1643,11 @@ class DbiDummy implements DbiExtension ], [ 'query' => 'SHOW FULL COLUMNS FROM `test_db`.`test_table`', - 'columns' => ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'], + 'columns' => ['Field', 'Type', 'Collation', 'Null', 'Key', 'Default', 'Extra', 'Privileges', 'Comment'], 'result' => [ - ['id', 'int(11)', 'NO', 'PRI', 'NULL', 'auto_increment'], - ['name', 'varchar(20)', 'NO', '', 'NULL', ''], - ['datetimefield', 'datetime', 'NO', '', 'NULL', ''], + ['id', 'int(11)', null, 'NO', 'PRI', 'NULL', 'auto_increment', '', ''], + ['name', 'varchar(20)', null, 'NO', '', 'NULL', '', '', ''], + ['datetimefield', 'datetime', null, 'NO', '', 'NULL', '', '', ''], ], ], [