3 * Functionality for the navigation tree
6 declare(strict_types
=1);
8 namespace PhpMyAdmin\Navigation\Nodes
;
14 use function in_array
;
18 * Represents a columns node in the navigation tree
20 class NodeTable
extends NodeDatabaseChild
23 * For the second IMG tag, used when rendering the node.
25 * @var array<string, string>|null
26 * @psalm-var array{image: string, title: string}|null
31 * Initialises the class
33 * @param string $name An identifier for the new node
34 * @param int $type Type of node, may be one of CONTAINER or OBJECT
35 * @param bool $isGroup Whether this object has been created
36 * while grouping nodes
38 public function __construct($name, $type = Node
::OBJECT, $isGroup = false)
40 parent
::__construct($name, $type, $isGroup);
41 $icon = $this->addIcon(
42 Util
::getScriptNameForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable'], 'table')
48 $this->secondIcon
= $this->addIcon(
49 Util
::getScriptNameForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], 'table')
51 $title = (string) Util
::getTitleForTarget($GLOBALS['cfg']['DefaultTabTable']);
52 $this->title
= $title;
56 'route' => Util
::getUrlForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'),
57 'params' => ['pos' => 0, 'db' => null, 'table' => null],
60 'route' => Util
::getUrlForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable'], 'table'),
61 'params' => ['db' => null, 'table' => null],
64 'route' => Util
::getUrlForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], 'table'),
65 'params' => ['db' => null, 'table' => null],
67 'title' => $this->title
,
69 $this->classes
= 'nav_node_table';
70 $this->urlParamName
= 'table';
74 * Returns the number of children of type $type present inside this container
75 * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase
76 * and PhpMyAdmin\Navigation\Nodes\NodeTable classes
78 * @param string $type The type of item we are looking for
79 * ('columns' or 'indexes')
80 * @param string $searchClause A string used to filter the results of the query
84 public function getPresence($type = '', $searchClause = '')
87 $db = $this->realParent()->realName
;
88 $table = $this->realName
;
91 if (! $GLOBALS['cfg']['Server']['DisableIS']) {
92 $db = $GLOBALS['dbi']->escapeString($db);
93 $table = $GLOBALS['dbi']->escapeString($table);
94 $query = 'SELECT COUNT(*) ';
95 $query .= 'FROM `INFORMATION_SCHEMA`.`COLUMNS` ';
96 $query .= "WHERE `TABLE_NAME`='" . $table . "' ";
97 $query .= "AND `TABLE_SCHEMA`='" . $db . "'";
98 $retval = (int) $GLOBALS['dbi']->fetchValue($query);
100 $db = Util
::backquote($db);
101 $table = Util
::backquote($table);
102 $query = 'SHOW COLUMNS FROM ' . $table . ' FROM ' . $db . '';
103 $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query);
108 $db = Util
::backquote($db);
109 $table = Util
::backquote($table);
110 $query = 'SHOW INDEXES FROM ' . $table . ' FROM ' . $db;
111 $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query);
114 if (! $GLOBALS['cfg']['Server']['DisableIS']) {
115 $db = $GLOBALS['dbi']->escapeString($db);
116 $table = $GLOBALS['dbi']->escapeString($table);
117 $query = 'SELECT COUNT(*) ';
118 $query .= 'FROM `INFORMATION_SCHEMA`.`TRIGGERS` ';
119 $query .= 'WHERE `EVENT_OBJECT_SCHEMA` '
120 . Util
::getCollateForIS() . "='" . $db . "' ";
121 $query .= 'AND `EVENT_OBJECT_TABLE` '
122 . Util
::getCollateForIS() . "='" . $table . "'";
123 $retval = (int) $GLOBALS['dbi']->fetchValue($query);
125 $db = Util
::backquote($db);
126 $table = $GLOBALS['dbi']->escapeString($table);
127 $query = 'SHOW TRIGGERS FROM ' . $db . " WHERE `Table` = '" . $table . "'";
128 $retval = (int) $GLOBALS['dbi']->queryAndGetNumRows($query);
140 * Returns the names of children of type $type present inside this container
141 * This method is overridden by the PhpMyAdmin\Navigation\Nodes\NodeDatabase
142 * and PhpMyAdmin\Navigation\Nodes\NodeTable classes
144 * @param string $type The type of item we are looking for
145 * ('tables', 'views', etc)
146 * @param int $pos The offset of the list within the results
147 * @param string $searchClause A string used to filter the results of the query
151 public function getData($type, $pos, $searchClause = '')
153 $maxItems = $GLOBALS['cfg']['MaxNavigationItems'];
155 $db = $this->realParent()->realName
;
156 $table = $this->realName
;
159 if (! $GLOBALS['cfg']['Server']['DisableIS']) {
160 $db = $GLOBALS['dbi']->escapeString($db);
161 $table = $GLOBALS['dbi']->escapeString($table);
162 $query = 'SELECT `COLUMN_NAME` AS `name` ';
163 $query .= ',`COLUMN_KEY` AS `key` ';
164 $query .= ',`DATA_TYPE` AS `type` ';
165 $query .= ',`COLUMN_DEFAULT` AS `default` ';
166 $query .= ",IF (`IS_NULLABLE` = 'NO', '', 'nullable') AS `nullable` ";
167 $query .= 'FROM `INFORMATION_SCHEMA`.`COLUMNS` ';
168 $query .= "WHERE `TABLE_NAME`='" . $table . "' ";
169 $query .= "AND `TABLE_SCHEMA`='" . $db . "' ";
170 $query .= 'ORDER BY `COLUMN_NAME` ASC ';
171 $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems;
172 $retval = $GLOBALS['dbi']->fetchResult($query);
176 $db = Util
::backquote($db);
177 $table = Util
::backquote($table);
178 $query = 'SHOW COLUMNS FROM ' . $table . ' FROM ' . $db;
179 $handle = $GLOBALS['dbi']->tryQuery($query);
180 if ($handle === false) {
185 if ($handle->seek($pos)) {
186 while ($arr = $handle->fetchAssoc()) {
187 if ($count >= $maxItems) {
192 'name' => $arr['Field'],
193 'key' => $arr['Key'],
194 'type' => Util
::extractColumnSpec($arr['Type'])['type'],
195 'default' => $arr['Default'],
196 'nullable' => ($arr['Null'] === 'NO' ?
'' : 'nullable'),
204 $db = Util
::backquote($db);
205 $table = Util
::backquote($table);
206 $query = 'SHOW INDEXES FROM ' . $table . ' FROM ' . $db;
207 $handle = $GLOBALS['dbi']->tryQuery($query);
208 if ($handle === false) {
213 foreach ($handle as $arr) {
214 if (in_array($arr['Key_name'], $retval)) {
218 if ($pos <= 0 && $count < $maxItems) {
219 $retval[] = $arr['Key_name'];
228 if (! $GLOBALS['cfg']['Server']['DisableIS']) {
229 $db = $GLOBALS['dbi']->escapeString($db);
230 $table = $GLOBALS['dbi']->escapeString($table);
231 $query = 'SELECT `TRIGGER_NAME` AS `name` ';
232 $query .= 'FROM `INFORMATION_SCHEMA`.`TRIGGERS` ';
233 $query .= 'WHERE `EVENT_OBJECT_SCHEMA` '
234 . Util
::getCollateForIS() . "='" . $db . "' ";
235 $query .= 'AND `EVENT_OBJECT_TABLE` '
236 . Util
::getCollateForIS() . "='" . $table . "' ";
237 $query .= 'ORDER BY `TRIGGER_NAME` ASC ';
238 $query .= 'LIMIT ' . intval($pos) . ', ' . $maxItems;
239 $retval = $GLOBALS['dbi']->fetchResult($query);
243 $db = Util
::backquote($db);
244 $table = $GLOBALS['dbi']->escapeString($table);
245 $query = 'SHOW TRIGGERS FROM ' . $db . " WHERE `Table` = '" . $table . "'";
246 $handle = $GLOBALS['dbi']->tryQuery($query);
247 if ($handle === false) {
252 if ($handle->seek($pos)) {
253 while ($arr = $handle->fetchAssoc()) {
254 if ($count >= $maxItems) {
258 $retval[] = $arr['Trigger'];
272 * Returns the type of the item represented by the node.
274 * @return string type of the item
276 protected function getItemType()
282 * Add an icon to navigation tree
284 * @param string $page Page name to redirect
286 * @return array<string, string>|null
287 * @psalm-return array{image: string, title: string}|null
289 private function addIcon(string $page): ?
array
296 case Url
::getFromRoute('/table/structure'):
297 return ['image' => 'b_props', 'title' => __('Structure')];
299 case Url
::getFromRoute('/table/search'):
300 return ['image' => 'b_search', 'title' => __('Search')];
302 case Url
::getFromRoute('/table/change'):
303 return ['image' => 'b_insrow', 'title' => __('Insert')];
305 case Url
::getFromRoute('/table/sql'):
306 return ['image' => 'b_sql', 'title' => __('SQL')];
308 case Url
::getFromRoute('/sql'):
309 return ['image' => 'b_browse', 'title' => __('Browse')];