3 * Recent and Favorite table list handling
6 declare(strict_types
=1);
10 use PhpMyAdmin\Html\Generator
;
11 use const SORT_REGULAR
;
12 use function array_key_exists
;
13 use function array_merge
;
14 use function array_pop
;
15 use function array_unique
;
16 use function array_unshift
;
18 use function htmlspecialchars
;
19 use function json_decode
;
20 use function json_encode
;
26 * Handles the recently used and favorite tables.
28 * @TODO Change the release version in table pma_recent
29 * (#recent in documentation)
31 class RecentFavoriteTable
34 * Reference to session variable containing recently used or favorite tables.
42 * Defines type of action, Favorite or Recent table.
50 * RecentFavoriteTable instances.
55 private static $instances = [];
61 * Creates a new instance of RecentFavoriteTable
63 * @param string $type the table type
67 private function __construct($type)
71 $this->relation
= new Relation($dbi);
72 $this->tableType
= $type;
73 $server_id = $GLOBALS['server'];
74 if (! isset($_SESSION['tmpval'][$this->tableType
. 'Tables'][$server_id])
76 $_SESSION['tmpval'][$this->tableType
. 'Tables'][$server_id]
77 = $this->getPmaTable() ?
$this->getFromDb() : [];
80 =& $_SESSION['tmpval'][$this->tableType
. 'Tables'][$server_id];
84 * Returns class instance.
86 * @param string $type the table type
88 * @return RecentFavoriteTable
90 public static function getInstance($type)
92 if (! array_key_exists($type, self
::$instances)) {
93 self
::$instances[$type] = new RecentFavoriteTable($type);
96 return self
::$instances[$type];
100 * Returns the recent/favorite tables array
104 public function getTables()
106 return $this->tables
;
110 * Returns recently used tables or favorite from phpMyAdmin database.
114 public function getFromDb()
118 // Read from phpMyAdmin database, if recent tables is not in session
120 = ' SELECT `tables` FROM ' . $this->getPmaTable() .
121 " WHERE `username` = '" . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'";
124 $result = $this->relation
->queryAsControlUser($sql_query, false);
126 $row = $dbi->fetchArray($result);
127 if (isset($row[0])) {
128 $return = json_decode($row[0], true);
136 * Save recent/favorite tables into phpMyAdmin database.
138 * @return true|Message
140 public function saveToDb()
144 $username = $GLOBALS['cfg']['Server']['user'];
146 = ' REPLACE INTO ' . $this->getPmaTable() . ' (`username`, `tables`)' .
147 " VALUES ('" . $dbi->escapeString($username) . "', '"
148 . $dbi->escapeString(
149 json_encode($this->tables
)
152 $success = $dbi->tryQuery($sql_query, DatabaseInterface
::CONNECT_CONTROL
);
156 switch ($this->tableType
) {
158 $error_msg = __('Could not save recent table!');
162 $error_msg = __('Could not save favorite table!');
165 $message = Message
::error($error_msg);
166 $message->addMessage(
168 $dbi->getError(DatabaseInterface
::CONNECT_CONTROL
)
180 * Trim recent.favorite table according to the
181 * NumRecentTables/NumFavoriteTables configuration.
183 * @return bool True if trimming occurred
185 public function trim()
188 $GLOBALS['cfg']['Num' . ucfirst($this->tableType
) . 'Tables'],
191 $trimming_occurred = count($this->tables
) > $max;
192 while (count($this->tables
) > $max) {
193 array_pop($this->tables
);
196 return $trimming_occurred;
204 public function getHtmlList()
207 if (count($this->tables
)) {
208 if ($this->tableType
=== 'recent') {
209 foreach ($this->tables
as $table) {
210 $html .= '<li class="warp_link">';
211 $recent_url = Url
::getFromRoute('/table/recent-favorite', [
212 'db' => $table['db'],
213 'table' => $table['table'],
215 $html .= '<a href="' . $recent_url . '">`'
216 . htmlspecialchars($table['db']) . '`.`'
217 . htmlspecialchars($table['table']) . '`</a>';
221 foreach ($this->tables
as $table) {
222 $html .= '<li class="warp_link">';
224 $html .= '<a class="ajax favorite_table_anchor" ';
225 $fav_rm_url = Url
::getFromRoute('/database/structure/favorite-table', [
226 'db' => $table['db'],
227 'ajax_request' => true,
228 'favorite_table' => $table['table'],
229 'remove_favorite' => true,
231 $html .= 'href="' . $fav_rm_url
232 . '" title="' . __('Remove from Favorites')
233 . '" data-favtargetn="'
234 . md5($table['db'] . '.' . $table['table'])
236 . Generator
::getIcon('b_favorite')
239 $table_url = Url
::getFromRoute('/table/recent-favorite', [
240 'db' => $table['db'],
241 'table' => $table['table'],
243 $html .= '<a href="' . $table_url . '">`'
244 . htmlspecialchars($table['db']) . '`.`'
245 . htmlspecialchars($table['table']) . '`</a>';
250 $html .= '<li class="warp_link">'
251 . ($this->tableType
=== 'recent'
252 ?
__('There are no recent tables.')
253 : __('There are no favorite tables.'))
265 public function getHtml()
267 $html = '<div class="drop_list">';
268 if ($this->tableType
=== 'recent') {
269 $html .= '<button title="' . __('Recent tables')
270 . '" class="drop_button btn">'
271 . __('Recent') . '</button><ul id="pma_recent_list">';
273 $html .= '<button title="' . __('Favorite tables')
274 . '" class="drop_button btn">'
275 . __('Favorites') . '</button><ul id="pma_favorite_list">';
277 $html .= $this->getHtmlList();
278 $html .= '</ul></div>';
284 * Add recently used or favorite tables.
286 * @param string $db database name where the table is located
287 * @param string $table table name
289 * @return true|Message True if success, Message if not
291 public function add($db, $table)
295 // If table does not exist, do not add._getPmaTable()
296 if (! $dbi->getColumns($db, $table)) {
301 $table_arr['db'] = $db;
302 $table_arr['table'] = $table;
304 // add only if this is new table
305 if (! isset($this->tables
[0]) ||
$this->tables
[0] != $table_arr) {
306 array_unshift($this->tables
, $table_arr);
307 $this->tables
= array_merge(array_unique($this->tables
, SORT_REGULAR
));
309 if ($this->getPmaTable()) {
310 return $this->saveToDb();
318 * Removes recent/favorite tables that don't exist.
320 * @param string $db database
321 * @param string $table table
323 * @return bool|Message True if invalid and removed, False if not invalid,
324 * Message if error while removing
326 public function removeIfInvalid($db, $table)
330 foreach ($this->tables
as $tbl) {
331 if ($tbl['db'] != $db ||
$tbl['table'] != $table) {
335 // TODO Figure out a better way to find the existence of a table
336 if (! $dbi->getColumns($tbl['db'], $tbl['table'])) {
337 return $this->remove($tbl['db'], $tbl['table']);
345 * Remove favorite tables.
347 * @param string $db database name where the table is located
348 * @param string $table table name
350 * @return true|Message True if success, Message if not
352 public function remove($db, $table)
354 foreach ($this->tables
as $key => $value) {
355 if ($value['db'] != $db ||
$value['table'] != $table) {
359 unset($this->tables
[$key]);
361 if ($this->getPmaTable()) {
362 return $this->saveToDb();
369 * Generate Html for sync Favorite tables anchor. (from localStorage to pmadb)
373 public function getHtmlSyncFavoriteTables()
376 $server_id = $GLOBALS['server'];
377 if ($server_id == 0) {
380 $cfgRelation = $this->relation
->getRelationsParam();
381 // Not to show this once list is synchronized.
382 if ($cfgRelation['favoritework'] && ! isset($_SESSION['tmpval']['favorites_synced'][$server_id])) {
383 $url = Url
::getFromRoute('/database/structure/favorite-table', [
384 'ajax_request' => true,
385 'favorite_table' => true,
386 'sync_favorite_tables' => true,
388 $retval = '<a class="hide" id="sync_favorite_tables"';
389 $retval .= ' href="' . $url . '"></a>';
396 * Generate Html to update recent tables.
398 * @return string html
400 public static function getHtmlUpdateRecentTables()
402 $retval = '<a class="hide" id="update_recent_tables" href="';
403 $retval .= Url
::getFromRoute('/recent-table', [
404 'ajax_request' => true,
405 'recent_table' => true,
413 * Return the name of the configuration storage table
415 * @return string|null pma table name
417 private function getPmaTable(): ?
string
419 $cfgRelation = $this->relation
->getRelationsParam();
420 if (! $cfgRelation['recentwork']) {
424 if (! empty($cfgRelation['db'])
425 && ! empty($cfgRelation[$this->tableType
])
427 return Util
::backquote($cfgRelation['db']) . '.'
428 . Util
::backquote($cfgRelation[$this->tableType
]);