Replace `global` keyword with `$GLOBALS`
[phpmyadmin.git] / libraries / classes / Navigation / Nodes / NodeTable.php
blob9856ac2c27797987cbd5a7d6fbc7911dbfa4de4e
1 <?php
2 /**
3 * Functionality for the navigation tree
4 */
6 declare(strict_types=1);
8 namespace PhpMyAdmin\Navigation\Nodes;
10 use PhpMyAdmin\Url;
11 use PhpMyAdmin\Util;
13 use function __;
14 use function in_array;
15 use function intval;
17 /**
18 * Represents a columns node in the navigation tree
20 class NodeTable extends NodeDatabaseChild
22 /**
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
28 public $secondIcon;
30 /**
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')
44 if ($icon !== null) {
45 $this->icon = $icon;
48 $this->secondIcon = $this->addIcon(
49 Util::getScriptNameForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable2'], 'table')
51 $title = (string) Util::getTitleForTarget($GLOBALS['cfg']['DefaultTabTable']);
52 $this->title = $title;
54 $this->links = [
55 'text' => [
56 'route' => Util::getUrlForOption($GLOBALS['cfg']['DefaultTabTable'], 'table'),
57 'params' => ['pos' => 0, 'db' => null, 'table' => null],
59 'icon' => [
60 'route' => Util::getUrlForOption($GLOBALS['cfg']['NavigationTreeDefaultTabTable'], 'table'),
61 'params' => ['db' => null, 'table' => null],
63 'second_icon' => [
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';
73 /**
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
82 * @return int
84 public function getPresence($type = '', $searchClause = '')
86 $retval = 0;
87 $db = $this->realParent()->realName;
88 $table = $this->realName;
89 switch ($type) {
90 case 'columns':
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);
99 } else {
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);
106 break;
107 case 'indexes':
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);
112 break;
113 case 'triggers':
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);
124 } else {
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);
131 break;
132 default:
133 break;
136 return $retval;
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
149 * @return array
151 public function getData($type, $pos, $searchClause = '')
153 $maxItems = $GLOBALS['cfg']['MaxNavigationItems'];
154 $retval = [];
155 $db = $this->realParent()->realName;
156 $table = $this->realName;
157 switch ($type) {
158 case 'columns':
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);
173 break;
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) {
181 break;
184 $count = 0;
185 if ($handle->seek($pos)) {
186 while ($arr = $handle->fetchAssoc()) {
187 if ($count >= $maxItems) {
188 break;
191 $retval[] = [
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'),
198 $count++;
202 break;
203 case 'indexes':
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) {
209 break;
212 $count = 0;
213 foreach ($handle as $arr) {
214 if (in_array($arr['Key_name'], $retval)) {
215 continue;
218 if ($pos <= 0 && $count < $maxItems) {
219 $retval[] = $arr['Key_name'];
220 $count++;
223 $pos--;
226 break;
227 case 'triggers':
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);
240 break;
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) {
248 break;
251 $count = 0;
252 if ($handle->seek($pos)) {
253 while ($arr = $handle->fetchAssoc()) {
254 if ($count >= $maxItems) {
255 break;
258 $retval[] = $arr['Trigger'];
259 $count++;
263 break;
264 default:
265 break;
268 return $retval;
272 * Returns the type of the item represented by the node.
274 * @return string type of the item
276 protected function getItemType()
278 return 'table';
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
291 if (empty($page)) {
292 return null;
295 switch ($page) {
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')];
312 return null;