Merge #20025 - Nodes refactoring
Pull-request: #20025 Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
commit
cd1b3ad028
@ -7765,85 +7765,7 @@ parameters:
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
|
||||
identifier: empty.notAllowed
|
||||
count: 4
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Method PhpMyAdmin\\Navigation\\Nodes\\Node\:\:getDatabasesToSearch\(\) should return array\<mixed\> but returns list\<string\>\|string\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$array of function sort expects TArray of array\<string\>, array\<string\>\|string given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$db of method PhpMyAdmin\\Navigation\\Nodes\\Node\:\:isHideDb\(\) expects string, string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 4
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$haystack of function strstr expects string, string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 4
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$str of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:quoteString\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 5
|
||||
path: src/Navigation/Nodes/Node.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\." between mixed and ''\)'' results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\.\=" between mixed and '' \('' results in an error\.$#'
|
||||
identifier: assignOp.invalid
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\.\=" between mixed and '', '' results in an error\.$#'
|
||||
identifier: assignOp.invalid
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
|
||||
identifier: empty.notAllowed
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$item of method PhpMyAdmin\\Navigation\\Nodes\\NodeColumn\:\:getDisplayName\(\) expects array\<string, mixed\>, array\<mixed\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$key of method PhpMyAdmin\\Navigation\\Nodes\\NodeColumn\:\:getColumnIcon\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$name of method PhpMyAdmin\\Navigation\\Nodes\\Node\:\:__construct\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$value of method PhpMyAdmin\\Navigation\\Nodes\\NodeColumn\:\:getTruncateValue\(\) expects string, mixed given\.$#'
|
||||
message: '#^Parameter \#2 \$name of method PhpMyAdmin\\Navigation\\Nodes\\Node\:\:__construct\(\) expects string, string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeColumn.php
|
||||
@ -7893,6 +7815,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeTable.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$item of class PhpMyAdmin\\Navigation\\Nodes\\NodeColumn constructor expects array\{name\: string\|null, key\: string, type\: string\|null, default\: string\|null, nullable\: string\}, array\<string\|null\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Navigation/Nodes/NodeTable.php
|
||||
|
||||
-
|
||||
message: '#^Method PhpMyAdmin\\Navigation\\Nodes\\ObjectFetcher\:\:getEventsFromDb\(\) should return array\<string\> but returns list\<string\|null\>\.$#'
|
||||
identifier: return.type
|
||||
@ -16335,7 +16263,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 2
|
||||
count: 7
|
||||
path: tests/unit/Navigation/Nodes/NodeTableTest.php
|
||||
|
||||
-
|
||||
@ -16344,13 +16272,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 7
|
||||
path: tests/unit/Navigation/Nodes/NodeTest.php
|
||||
|
||||
-
|
||||
message: '#^Property PhpMyAdmin\\Config\:\:\$selectedServer \(array\{host\: string, port\: string, socket\: string, ssl\: bool, ssl_key\: string\|null, ssl_cert\: string\|null, ssl_ca\: string\|null, ssl_ca_path\: string\|null, \.\.\.\}\) does not accept array\{host\: string, port\: string, socket\: string, ssl\: bool, ssl_key\: string\|null, ssl_cert\: string\|null, ssl_ca\: string\|null, ssl_ca_path\: string\|null, \.\.\.\}\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 3
|
||||
count: 8
|
||||
path: tests/unit/Navigation/Nodes/NodeTest.php
|
||||
|
||||
-
|
||||
|
||||
@ -5276,67 +5276,16 @@
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
<MixedArgument>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
</MixedArgument>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
<code><![CDATA[$db]]></code>
|
||||
</MixedAssignment>
|
||||
<PossiblyInvalidArgument>
|
||||
<code><![CDATA[$databases]]></code>
|
||||
</PossiblyInvalidArgument>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayOffset>
|
||||
<code><![CDATA[$prefixMap]]></code>
|
||||
<code><![CDATA[$prefixMap]]></code>
|
||||
<code><![CDATA[$prefixMap]]></code>
|
||||
<code><![CDATA[$prefixMap]]></code>
|
||||
</PossiblyNullArrayOffset>
|
||||
<PossiblyNullOperand>
|
||||
<code><![CDATA[$arr[0]]]></code>
|
||||
</PossiblyNullOperand>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<code><![CDATA[empty($this->config->selectedServer['hide_db'])]]></code>
|
||||
<code><![CDATA[empty($this->config->selectedServer['hide_db'])]]></code>
|
||||
<code><![CDATA[empty($this->config->selectedServer['only_db'])]]></code>
|
||||
<code><![CDATA[empty($this->config->selectedServer['only_db'])]]></code>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
</file>
|
||||
<file src="src/Navigation/Nodes/NodeColumn.php">
|
||||
<MixedArgument>
|
||||
<code><![CDATA[$item['key']]]></code>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$item['name']]]></code>
|
||||
<code><![CDATA[$value]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArgumentTypeCoercion>
|
||||
<code><![CDATA[$item]]></code>
|
||||
</MixedArgumentTypeCoercion>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$retval]]></code>
|
||||
<code><![CDATA[$value]]></code>
|
||||
</MixedAssignment>
|
||||
<MixedOperand>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullOperand>
|
||||
<code><![CDATA[$retval]]></code>
|
||||
<code><![CDATA[$retval]]></code>
|
||||
<code><![CDATA[$retval]]></code>
|
||||
</MixedOperand>
|
||||
</PossiblyNullOperand>
|
||||
</file>
|
||||
<file src="src/Navigation/Nodes/NodeDatabase.php">
|
||||
<DeprecatedMethod>
|
||||
@ -5358,6 +5307,9 @@
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
<MixedArgumentTypeCoercion>
|
||||
<code><![CDATA[$row]]></code>
|
||||
</MixedArgumentTypeCoercion>
|
||||
<PossiblyInvalidPropertyFetch>
|
||||
<code><![CDATA[$this->getRealParent()->realName]]></code>
|
||||
<code><![CDATA[$this->getRealParent()->realName]]></code>
|
||||
@ -10503,6 +10455,11 @@
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="tests/unit/Navigation/Nodes/NodeTest.php">
|
||||
@ -10514,11 +10471,8 @@
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
<InvalidPropertyAssignmentValue>
|
||||
<code><![CDATA[$config->selectedServer]]></code>
|
||||
<code><![CDATA[$config->selectedServer]]></code>
|
||||
</InvalidPropertyAssignmentValue>
|
||||
</file>
|
||||
<file src="tests/unit/Navigation/Nodes/ObjectFetcherTest.php">
|
||||
<DeprecatedMethod>
|
||||
|
||||
@ -225,8 +225,8 @@ class NavigationTree
|
||||
return (int) $this->dbi->fetchValue(
|
||||
sprintf(
|
||||
$query,
|
||||
$this->config->settings['FirstLevelNavigationItems'],
|
||||
$this->config->settings['FirstLevelNavigationItems'],
|
||||
$this->config->config->FirstLevelNavigationItems,
|
||||
$this->config->config->FirstLevelNavigationItems,
|
||||
$this->dbi->quoteString($this->config->settings['NavigationTreeDbSeparator']),
|
||||
$this->dbi->quoteString(Current::$database),
|
||||
),
|
||||
@ -277,7 +277,7 @@ class NavigationTree
|
||||
}
|
||||
}
|
||||
|
||||
$navItems = $this->config->settings['FirstLevelNavigationItems'];
|
||||
$navItems = $this->config->config->FirstLevelNavigationItems;
|
||||
|
||||
return (int) floor(count($prefixMap) / $navItems) * $navItems;
|
||||
}
|
||||
@ -1129,7 +1129,7 @@ class NavigationTree
|
||||
['server' => Current::$server],
|
||||
Url::getFromRoute('/navigation'),
|
||||
'frame_navigation',
|
||||
$this->config->settings['FirstLevelNavigationItems'],
|
||||
$this->config->config->FirstLevelNavigationItems,
|
||||
'pos',
|
||||
['dbselector'],
|
||||
);
|
||||
@ -1278,7 +1278,7 @@ class NavigationTree
|
||||
['server' => Current::$server],
|
||||
Url::getFromRoute('/navigation'),
|
||||
'frame_navigation',
|
||||
$this->config->settings['FirstLevelNavigationItems'],
|
||||
$this->config->config->FirstLevelNavigationItems,
|
||||
'pos',
|
||||
['dbselector'],
|
||||
);
|
||||
|
||||
@ -318,7 +318,7 @@ class Node
|
||||
int $pos,
|
||||
string $searchClause = '',
|
||||
): array {
|
||||
if (isset($this->config->selectedServer['DisableIS']) && ! $this->config->selectedServer['DisableIS']) {
|
||||
if (! $this->config->selectedServer['DisableIS']) {
|
||||
return $this->getDataFromInfoSchema($pos, $searchClause);
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ class Node
|
||||
! $this->config->settings['NavigationTreeEnableGrouping']
|
||||
|| ! $this->config->settings['ShowDatabasesNavigationAsTree']
|
||||
) {
|
||||
if (isset($this->config->selectedServer['DisableIS']) && ! $this->config->selectedServer['DisableIS']) {
|
||||
if (! $this->config->selectedServer['DisableIS']) {
|
||||
$query = 'SELECT COUNT(*) ';
|
||||
$query .= 'FROM INFORMATION_SCHEMA.SCHEMATA ';
|
||||
$query .= $this->getWhereClause('SCHEMA_NAME', $searchClause);
|
||||
@ -392,14 +392,15 @@ class Node
|
||||
continue;
|
||||
}
|
||||
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
if ($this->isHideDb($arr[0])) {
|
||||
/** @var string $value */
|
||||
foreach ($handle->fetchAllColumn() as $value) {
|
||||
if ($this->isHideDb($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = strstr($arr[0], $dbSeparator, true);
|
||||
$prefix = strstr($value, $dbSeparator, true);
|
||||
if ($prefix === false) {
|
||||
$prefix = $arr[0];
|
||||
$prefix = $value;
|
||||
}
|
||||
|
||||
$prefixMap[$prefix] = 1;
|
||||
@ -414,10 +415,11 @@ class Node
|
||||
$query .= $this->getWhereClause('Database', $searchClause);
|
||||
$handle = $dbi->tryQuery($query);
|
||||
if ($handle !== false) {
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
$prefix = strstr($arr[0], $dbSeparator, true);
|
||||
/** @var string $value */
|
||||
foreach ($handle->fetchAllColumn() as $value) {
|
||||
$prefix = strstr($value, $dbSeparator, true);
|
||||
if ($prefix === false) {
|
||||
$prefix = $arr[0];
|
||||
$prefix = $value;
|
||||
}
|
||||
|
||||
$prefixMap[$prefix] = 1;
|
||||
@ -434,7 +436,7 @@ class Node
|
||||
*/
|
||||
private function isHideDb(string $db): bool
|
||||
{
|
||||
return ! empty($this->config->selectedServer['hide_db'])
|
||||
return $this->config->selectedServer['hide_db'] !== ''
|
||||
&& preg_match('/' . $this->config->selectedServer['hide_db'] . '/', $db) === 1;
|
||||
}
|
||||
|
||||
@ -446,15 +448,15 @@ class Node
|
||||
*
|
||||
* @param string $searchClause search clause
|
||||
*
|
||||
* @return mixed[] array of databases
|
||||
* @return string[] array of databases
|
||||
*/
|
||||
private function getDatabasesToSearch(UserPrivileges $userPrivileges, string $searchClause): array
|
||||
{
|
||||
$databases = [];
|
||||
if ($searchClause !== '') {
|
||||
$databases = ['%' . DatabaseInterface::getInstance()->escapeMysqlWildcards($searchClause) . '%'];
|
||||
} elseif (! empty($this->config->selectedServer['only_db'])) {
|
||||
$databases = $this->config->selectedServer['only_db'];
|
||||
} elseif ($this->config->selectedServer['only_db'] !== '') {
|
||||
$databases = (array) $this->config->selectedServer['only_db'];
|
||||
} elseif ($userPrivileges->databasesToTest !== false && $userPrivileges->databasesToTest !== []) {
|
||||
$databases = $userPrivileges->databasesToTest;
|
||||
}
|
||||
@ -480,12 +482,12 @@ class Node
|
||||
. ' LIKE ' . $dbi->quoteString('%' . $dbi->escapeMysqlWildcards($searchClause) . '%') . ' ';
|
||||
}
|
||||
|
||||
if (! empty($this->config->selectedServer['hide_db'])) {
|
||||
if ($this->config->selectedServer['hide_db'] !== '') {
|
||||
$whereClause .= 'AND ' . Util::backquote($columnName)
|
||||
. ' NOT REGEXP ' . $dbi->quoteString($this->config->selectedServer['hide_db']) . ' ';
|
||||
}
|
||||
|
||||
if (! empty($this->config->selectedServer['only_db'])) {
|
||||
if ($this->config->selectedServer['only_db'] !== '') {
|
||||
if (is_string($this->config->selectedServer['only_db'])) {
|
||||
$this->config->selectedServer['only_db'] = [$this->config->selectedServer['only_db']];
|
||||
}
|
||||
@ -591,7 +593,7 @@ class Node
|
||||
*/
|
||||
private function getDataFromInfoSchema(int $pos, string $searchClause): array
|
||||
{
|
||||
$maxItems = $this->config->settings['FirstLevelNavigationItems'];
|
||||
$maxItems = $this->config->config->FirstLevelNavigationItems;
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
if (
|
||||
! $this->config->settings['NavigationTreeEnableGrouping']
|
||||
@ -632,7 +634,7 @@ class Node
|
||||
*/
|
||||
private function getDataFromShowDatabases(int $pos, string $searchClause): array
|
||||
{
|
||||
$maxItems = $this->config->settings['FirstLevelNavigationItems'];
|
||||
$maxItems = $this->config->config->FirstLevelNavigationItems;
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
if (
|
||||
! $this->config->settings['NavigationTreeEnableGrouping']
|
||||
@ -646,22 +648,7 @@ class Node
|
||||
return [];
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
if (! $handle->seek($pos)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$retval = [];
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
if ($count >= $maxItems) {
|
||||
break;
|
||||
}
|
||||
|
||||
$retval[] = $arr[0];
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
return array_slice($handle->fetchAllColumn(), $pos, $maxItems);
|
||||
}
|
||||
|
||||
$dbSeparator = $this->config->settings['NavigationTreeDbSeparator'];
|
||||
@ -673,10 +660,10 @@ class Node
|
||||
if ($handle !== false) {
|
||||
$prefixMap = [];
|
||||
$total = $pos + $maxItems;
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
$prefix = strstr($arr[0], $dbSeparator, true);
|
||||
while ($value = $handle->fetchValue()) {
|
||||
$prefix = strstr($value, $dbSeparator, true);
|
||||
if ($prefix === false) {
|
||||
$prefix = $arr[0];
|
||||
$prefix = $value;
|
||||
}
|
||||
|
||||
$prefixMap[$prefix] = 1;
|
||||
@ -710,11 +697,11 @@ class Node
|
||||
* @param int $pos The offset of the list within the results.
|
||||
* @param string $searchClause A string used to filter the results of the query.
|
||||
*
|
||||
* @return list<string|null>
|
||||
* @return list<string>
|
||||
*/
|
||||
private function getDataFromShowDatabasesLike(UserPrivileges $userPrivileges, int $pos, string $searchClause): array
|
||||
{
|
||||
$maxItems = $this->config->settings['FirstLevelNavigationItems'];
|
||||
$maxItems = $this->config->config->FirstLevelNavigationItems;
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
if (
|
||||
! $this->config->settings['NavigationTreeEnableGrouping']
|
||||
@ -728,17 +715,18 @@ class Node
|
||||
continue;
|
||||
}
|
||||
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
if ($this->isHideDb($arr[0])) {
|
||||
/** @var string $value */
|
||||
foreach ($handle->fetchAllColumn() as $value) {
|
||||
if ($this->isHideDb($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($arr[0], $retval, true)) {
|
||||
if (in_array($value, $retval, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($pos <= 0 && $count < $maxItems) {
|
||||
$retval[] = $arr[0];
|
||||
$retval[] = $value;
|
||||
$count++;
|
||||
}
|
||||
|
||||
@ -761,14 +749,15 @@ class Node
|
||||
continue;
|
||||
}
|
||||
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
if ($this->isHideDb($arr[0])) {
|
||||
/** @var string $value */
|
||||
foreach ($handle->fetchAllColumn() as $value) {
|
||||
if ($this->isHideDb($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = strstr($arr[0], $dbSeparator, true);
|
||||
$prefix = strstr($value, $dbSeparator, true);
|
||||
if ($prefix === false) {
|
||||
$prefix = $arr[0];
|
||||
$prefix = $value;
|
||||
}
|
||||
|
||||
$prefixMap[$prefix] = 1;
|
||||
@ -786,19 +775,20 @@ class Node
|
||||
continue;
|
||||
}
|
||||
|
||||
while ($arr = $handle->fetchRow()) {
|
||||
if ($this->isHideDb($arr[0])) {
|
||||
/** @var string $value */
|
||||
foreach ($handle->fetchAllColumn() as $value) {
|
||||
if ($this->isHideDb($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($arr[0], $retval, true)) {
|
||||
if (in_array($value, $retval, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($prefixes as $prefix) {
|
||||
$startsWith = str_starts_with($arr[0] . $dbSeparator, $prefix . $dbSeparator);
|
||||
$startsWith = str_starts_with($value . $dbSeparator, $prefix . $dbSeparator);
|
||||
if ($startsWith) {
|
||||
$retval[] = $arr[0];
|
||||
$retval[] = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ class NodeColumn extends Node
|
||||
{
|
||||
public string $displayName;
|
||||
|
||||
/** @param mixed[] $item array to identify the column node */
|
||||
/** @param array{name:string|null, key:string, type:string|null, default:string|null, nullable:string} $item */
|
||||
public function __construct(Config $config, array $item)
|
||||
{
|
||||
$this->displayName = $this->getDisplayName($item);
|
||||
@ -60,7 +60,7 @@ class NodeColumn extends Node
|
||||
/**
|
||||
* Get displayable name for navigation tree (key_type, data_type, default)
|
||||
*
|
||||
* @param array<string, mixed> $item Item is array containing required info
|
||||
* @param array{name:string|null, key:string, type:string|null, default:string|null, nullable:string} $item
|
||||
*
|
||||
* @return string Display name for navigation tree
|
||||
*/
|
||||
@ -69,7 +69,7 @@ class NodeColumn extends Node
|
||||
$retval = $item['name'];
|
||||
$isFirst = true;
|
||||
foreach ($item as $key => $value) {
|
||||
if (empty($value) || $key === 'name') {
|
||||
if ($value === null || $value === '' || $key === 'name') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ use PhpMyAdmin\UserPrivileges;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function in_array;
|
||||
use function array_slice;
|
||||
|
||||
/**
|
||||
* Represents a columns node in the navigation tree
|
||||
@ -127,7 +127,7 @@ class NodeTable extends NodeDatabaseChild
|
||||
$query .= 'FROM `INFORMATION_SCHEMA`.`COLUMNS` ';
|
||||
$query .= 'WHERE `TABLE_NAME`=' . $dbi->quoteString($table) . ' ';
|
||||
$query .= 'AND `TABLE_SCHEMA`=' . $dbi->quoteString($db) . ' ';
|
||||
$query .= 'ORDER BY `COLUMN_NAME` ASC ';
|
||||
$query .= 'ORDER BY `ORDINAL_POSITION` ASC ';
|
||||
$query .= 'LIMIT ' . $pos . ', ' . $maxItems;
|
||||
|
||||
$columnNodes = [];
|
||||
@ -144,26 +144,18 @@ class NodeTable extends NodeDatabaseChild
|
||||
return [];
|
||||
}
|
||||
|
||||
$retval = [];
|
||||
$count = 0;
|
||||
if ($handle->seek($pos)) {
|
||||
foreach ($handle as $arr) {
|
||||
if ($count >= $maxItems) {
|
||||
return $retval;
|
||||
}
|
||||
|
||||
$retval[] = new NodeColumn($this->config, [
|
||||
'name' => $arr['Field'],
|
||||
'key' => $arr['Key'],
|
||||
'type' => Util::extractColumnSpec($arr['Type'])['type'],
|
||||
'default' => $arr['Default'],
|
||||
'nullable' => $arr['Null'] === 'NO' ? '' : 'nullable',
|
||||
]);
|
||||
$count++;
|
||||
}
|
||||
$columnNodes = [];
|
||||
foreach (array_slice($handle->fetchAllAssoc(), $pos, $maxItems) as $arr) {
|
||||
$columnNodes[] = new NodeColumn($this->config, [
|
||||
'name' => $arr['Field'],
|
||||
'key' => $arr['Key'] ?? '',
|
||||
'type' => Util::extractColumnSpec($arr['Type'])['type'],
|
||||
'default' => $arr['Default'],
|
||||
'nullable' => $arr['Null'] === 'NO' ? '' : 'nullable',
|
||||
]);
|
||||
}
|
||||
|
||||
return $retval;
|
||||
return $columnNodes;
|
||||
}
|
||||
|
||||
/** @return NodeIndex[] */
|
||||
@ -178,24 +170,9 @@ class NodeTable extends NodeDatabaseChild
|
||||
return [];
|
||||
}
|
||||
|
||||
$indexNames = [];
|
||||
$count = 0;
|
||||
/** @var string $keyName */
|
||||
foreach ($handle as ['Key_name' => $keyName]) {
|
||||
if (in_array($keyName, $indexNames, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($pos <= 0 && $count < $maxItems) {
|
||||
$indexNames[] = $keyName;
|
||||
$count++;
|
||||
}
|
||||
|
||||
$pos--;
|
||||
}
|
||||
|
||||
$indexNodes = [];
|
||||
foreach ($indexNames as $indexName) {
|
||||
/** @var string $indexName */
|
||||
foreach (array_slice($handle->fetchAllAssoc(), $pos, $maxItems) as ['Key_name' => $indexName]) {
|
||||
$indexNodes[] = new NodeIndex($this->config, $indexName);
|
||||
}
|
||||
|
||||
@ -232,21 +209,13 @@ class NodeTable extends NodeDatabaseChild
|
||||
return [];
|
||||
}
|
||||
|
||||
$retval = [];
|
||||
$count = 0;
|
||||
if ($handle->seek($pos)) {
|
||||
/** @var string $triggerName */
|
||||
foreach ($handle as ['Trigger' => $triggerName]) {
|
||||
if ($count >= $maxItems) {
|
||||
return $retval;
|
||||
}
|
||||
|
||||
$retval[] = new NodeTrigger($this->config, $triggerName);
|
||||
$count++;
|
||||
}
|
||||
$triggerNodes = [];
|
||||
/** @var string $triggerName */
|
||||
foreach (array_slice($handle->fetchAllAssoc(), $pos, $maxItems) as ['Trigger' => $triggerName]) {
|
||||
$triggerNodes[] = new NodeTrigger($this->config, $triggerName);
|
||||
}
|
||||
|
||||
return $retval;
|
||||
return $triggerNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,8 +5,11 @@ declare(strict_types=1);
|
||||
namespace PhpMyAdmin\Tests\Navigation\Nodes;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Dbal\DatabaseInterface;
|
||||
use PhpMyAdmin\Navigation\Nodes\NodeDatabase;
|
||||
use PhpMyAdmin\Navigation\Nodes\NodeTable;
|
||||
use PhpMyAdmin\Tests\AbstractTestCase;
|
||||
use PhpMyAdmin\Tests\Stubs\DummyResult;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
@ -64,4 +67,166 @@ class NodeTableTest extends AbstractTestCase
|
||||
['/sql', 'b_browse', 'Browse'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetColumnsWithoutDisableIS(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$dbi->expects(self::once())
|
||||
->method('fetchResultSimple')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
['name' => 'foo1', 'type' => 'varchar(255)', 'key' => '', 'default' => '', 'nullable' => ''],
|
||||
['name' => 'foo2', 'type' => 'varchar(64)', 'key' => '', 'default' => '', 'nullable' => ''],
|
||||
['name' => 'foo3', 'type' => 'int(11)', 'key' => '', 'default' => '0', 'nullable' => ''],
|
||||
['name' => 'foo4', 'type' => 'text', 'key' => '', 'default' => '', 'nullable' => ''],
|
||||
],
|
||||
);
|
||||
|
||||
$nodeContainer = new NodeDatabase($config, 'DB');
|
||||
$nodeTable = new NodeTable($config, 'node');
|
||||
$nodeContainer->addChild($nodeTable);
|
||||
|
||||
$result = $nodeTable->getColumns($dbi, 1);
|
||||
self::assertCount(4, $result);
|
||||
|
||||
self::assertSame('foo1 (varchar(255))', $result[0]->displayName);
|
||||
self::assertSame('foo2 (varchar(64))', $result[1]->displayName);
|
||||
self::assertSame('foo3 (int(11), 0)', $result[2]->displayName);
|
||||
self::assertSame('foo4 (text)', $result[3]->displayName);
|
||||
}
|
||||
|
||||
public function testGetColumnsWithDisableIS(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = true;
|
||||
$config->set('MaxNavigationItems', 2);
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$resultStub = self::createMock(DummyResult::class);
|
||||
$dbi->expects(self::once())
|
||||
->method('tryQuery')
|
||||
->with('SHOW COLUMNS FROM `node` FROM `DB`')
|
||||
->willReturn($resultStub);
|
||||
$resultStub->expects(self::once())
|
||||
->method('fetchAllAssoc')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
['Field' => 'foo1', 'Type' => 'varchar(255)', 'Key' => '', 'Default' => '', 'Null' => 'NO'],
|
||||
['Field' => 'foo2', 'Type' => 'varchar(64)', 'Key' => '', 'Default' => '', 'Null' => 'NO'],
|
||||
['Field' => 'foo3', 'Type' => 'int(11)', 'Key' => '', 'Default' => '0', 'Null' => 'NO'],
|
||||
['Field' => 'foo4', 'Type' => 'text', 'Key' => '', 'Default' => '', 'Null' => 'NO'],
|
||||
],
|
||||
);
|
||||
|
||||
$nodeContainer = new NodeDatabase($config, 'DB');
|
||||
$nodeTable = new NodeTable($config, 'node');
|
||||
$nodeContainer->addChild($nodeTable);
|
||||
|
||||
$result = $nodeTable->getColumns($dbi, 1);
|
||||
self::assertCount(2, $result);
|
||||
|
||||
self::assertSame('foo2 (varchar)', $result[0]->displayName);
|
||||
self::assertSame('foo3 (int, 0)', $result[1]->displayName);
|
||||
}
|
||||
|
||||
public function testGetTriggersWithoutDisableIS(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$dbi->expects(self::once())
|
||||
->method('fetchSingleColumn')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
'foo1',
|
||||
'foo2',
|
||||
'foo3',
|
||||
'foo4',
|
||||
],
|
||||
);
|
||||
|
||||
$nodeContainer = new NodeDatabase($config, 'DB');
|
||||
$nodeTable = new NodeTable($config, 'node');
|
||||
$nodeContainer->addChild($nodeTable);
|
||||
|
||||
$result = $nodeTable->getTriggers($dbi, 1);
|
||||
self::assertCount(4, $result);
|
||||
|
||||
self::assertSame('foo1', $result[0]->name);
|
||||
self::assertSame('foo2', $result[1]->name);
|
||||
self::assertSame('foo3', $result[2]->name);
|
||||
self::assertSame('foo4', $result[3]->name);
|
||||
}
|
||||
|
||||
public function testGetTriggersWithDisableIS(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = true;
|
||||
$config->set('MaxNavigationItems', 2);
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$resultStub = self::createMock(DummyResult::class);
|
||||
$dbi->expects(self::once())->method('quoteString')
|
||||
->willReturnCallback(static fn (string $string): string => "'" . $string . "'");
|
||||
$dbi->expects(self::once())
|
||||
->method('tryQuery')
|
||||
->with('SHOW TRIGGERS FROM `DB` WHERE `Table` = \'node\'')
|
||||
->willReturn($resultStub);
|
||||
$resultStub->expects(self::once())
|
||||
->method('fetchAllAssoc')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
['Trigger' => 'foo1'],
|
||||
['Trigger' => 'foo2'],
|
||||
['Trigger' => 'foo3'],
|
||||
['Trigger' => 'foo4'],
|
||||
],
|
||||
);
|
||||
|
||||
$nodeContainer = new NodeDatabase($config, 'DB');
|
||||
$nodeTable = new NodeTable($config, 'node');
|
||||
$nodeContainer->addChild($nodeTable);
|
||||
|
||||
$result = $nodeTable->getTriggers($dbi, 1);
|
||||
self::assertCount(2, $result);
|
||||
|
||||
self::assertSame('foo2', $result[0]->name);
|
||||
self::assertSame('foo3', $result[1]->name);
|
||||
}
|
||||
|
||||
public function testGetIndexes(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = true;
|
||||
$config->set('MaxNavigationItems', 2);
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$resultStub = self::createMock(DummyResult::class);
|
||||
$dbi->expects(self::once())
|
||||
->method('tryQuery')
|
||||
->with('SHOW INDEXES FROM `node` FROM `DB`')
|
||||
->willReturn($resultStub);
|
||||
$resultStub->expects(self::once())
|
||||
->method('fetchAllAssoc')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
['Key_name' => 'foo1'],
|
||||
['Key_name' => 'foo2'],
|
||||
['Key_name' => 'foo3'],
|
||||
['Key_name' => 'foo4'],
|
||||
],
|
||||
);
|
||||
|
||||
$nodeContainer = new NodeDatabase($config, 'DB');
|
||||
$nodeTable = new NodeTable($config, 'node');
|
||||
$nodeContainer->addChild($nodeTable);
|
||||
|
||||
$result = $nodeTable->getIndexes($dbi, 1);
|
||||
self::assertCount(2, $result);
|
||||
|
||||
self::assertSame('foo2', $result[0]->name);
|
||||
self::assertSame('foo3', $result[1]->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,7 +295,7 @@ final class NodeTest extends AbstractTestCase
|
||||
"WHERE TRUE AND `SCHEMA_NAME` NOT REGEXP 'regexpHideDb' ",
|
||||
$method->invoke($node, 'SCHEMA_NAME'),
|
||||
);
|
||||
unset($config->selectedServer['hide_db']);
|
||||
$config->selectedServer['hide_db'] = '';
|
||||
|
||||
// When only_db directive is present and it's a single db
|
||||
$config->selectedServer['only_db'] = 'stringOnlyDb';
|
||||
@ -303,7 +303,7 @@ final class NodeTest extends AbstractTestCase
|
||||
"WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'stringOnlyDb' ) ",
|
||||
$method->invoke($node, 'SCHEMA_NAME'),
|
||||
);
|
||||
unset($config->selectedServer['only_db']);
|
||||
$config->selectedServer['only_db'] = '';
|
||||
|
||||
// When only_db directive is present and it's an array of dbs
|
||||
$config->selectedServer['only_db'] = ['onlyDbOne', 'onlyDbTwo'];
|
||||
@ -311,7 +311,7 @@ final class NodeTest extends AbstractTestCase
|
||||
'WHERE TRUE AND ( `SCHEMA_NAME` LIKE \'onlyDbOne\' OR `SCHEMA_NAME` LIKE \'onlyDbTwo\' ) ',
|
||||
$method->invoke($node, 'SCHEMA_NAME'),
|
||||
);
|
||||
unset($config->selectedServer['only_db']);
|
||||
$config->selectedServer['only_db'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -322,7 +322,7 @@ final class NodeTest extends AbstractTestCase
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = false;
|
||||
$config->settings['NavigationTreeEnableGrouping'] = true;
|
||||
$config->settings['FirstLevelNavigationItems'] = 20;
|
||||
$config->set('FirstLevelNavigationItems', 20);
|
||||
$config->settings['NavigationTreeDbSeparator'] = '_';
|
||||
|
||||
$expectedSql = 'SELECT `SCHEMA_NAME` ';
|
||||
@ -361,7 +361,7 @@ final class NodeTest extends AbstractTestCase
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = false;
|
||||
$config->settings['NavigationTreeEnableGrouping'] = false;
|
||||
$config->settings['FirstLevelNavigationItems'] = 20;
|
||||
$config->set('FirstLevelNavigationItems', 20);
|
||||
|
||||
$expectedSql = 'SELECT `SCHEMA_NAME` ';
|
||||
$expectedSql .= 'FROM `INFORMATION_SCHEMA`.`SCHEMATA` ';
|
||||
@ -386,7 +386,7 @@ final class NodeTest extends AbstractTestCase
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = true;
|
||||
$config->settings['NavigationTreeEnableGrouping'] = true;
|
||||
$config->settings['FirstLevelNavigationItems'] = 10;
|
||||
$config->set('FirstLevelNavigationItems', 2);
|
||||
$config->settings['NavigationTreeDbSeparator'] = '_';
|
||||
|
||||
$node = new Node($config, 'node');
|
||||
@ -398,9 +398,9 @@ final class NodeTest extends AbstractTestCase
|
||||
->method('tryQuery')
|
||||
->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' ")
|
||||
->willReturn($resultStub);
|
||||
$resultStub->expects(self::exactly(3))
|
||||
->method('fetchRow')
|
||||
->willReturn(['0' => 'db'], ['0' => 'aa_db'], []);
|
||||
$resultStub->expects(self::exactly(2))
|
||||
->method('fetchValue')
|
||||
->willReturn('db', 'aa_db', 'foo', '');
|
||||
|
||||
$dbi->expects(self::once())
|
||||
->method('fetchSingleColumn')
|
||||
@ -418,6 +418,40 @@ final class NodeTest extends AbstractTestCase
|
||||
$node->getData(new UserPrivileges(), 0, 'db');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests when DisableIS is true and navigation tree grouping disabled.
|
||||
*/
|
||||
public function testGetDataWithDisabledISAndGroupingDisabled(): void
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
$config->selectedServer['DisableIS'] = true;
|
||||
$config->settings['NavigationTreeEnableGrouping'] = false;
|
||||
$config->set('FirstLevelNavigationItems', 2);
|
||||
|
||||
$node = new Node($config, 'node');
|
||||
|
||||
$resultStub = self::createMock(DummyResult::class);
|
||||
|
||||
$dbi = self::createMock(DatabaseInterface::class);
|
||||
$dbi->expects(self::once())
|
||||
->method('tryQuery')
|
||||
->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' ")
|
||||
->willReturn($resultStub);
|
||||
$resultStub->expects(self::once())
|
||||
->method('fetchAllColumn')
|
||||
->willReturn(['db', 'aa_db', 'foo']);
|
||||
|
||||
$dbi->expects(self::once())->method('escapeMysqlWildcards')
|
||||
->willReturnArgument(0);
|
||||
$dbi->expects(self::once())->method('quoteString')
|
||||
->willReturnCallback(static fn (string $string): string => "'" . $string . "'");
|
||||
|
||||
DatabaseInterface::$instance = $dbi;
|
||||
$result = $node->getData(new UserPrivileges(), 0, 'db');
|
||||
|
||||
self::assertSame(['db', 'aa_db'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests when DisableIS is false and navigation tree grouping enabled.
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user