*/ private static $instances = []; /** @var Relation */ private $relation; /** * Creates a new instance of RecentFavoriteTable * * @param Template $template Template object * @param string $type the table type */ private function __construct(Template $template, string $type) { $this->template = $template; $this->relation = new Relation($GLOBALS['dbi']); $this->tableType = $type; $server_id = $GLOBALS['server']; if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id])) { $_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id] = $this->getPmaTable() ? $this->getFromDb() : []; } $this->tables =& $_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id]; } /** * Returns class instance. * * @param string $type the table type * @psalm-param 'favorite'|'recent' $type */ public static function getInstance(string $type): RecentFavoriteTable { if (! array_key_exists($type, self::$instances)) { $template = new Template(); self::$instances[$type] = new RecentFavoriteTable($template, $type); } return self::$instances[$type]; } /** * Returns the recent/favorite tables array * * @return array */ public function getTables() { return $this->tables; } /** * Returns recently used tables or favorite from phpMyAdmin database. * * @return array */ public function getFromDb(): array { // Read from phpMyAdmin database, if recent tables is not in session $sql_query = ' SELECT `tables` FROM ' . $this->getPmaTable() . " WHERE `username` = '" . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']) . "'"; $result = $GLOBALS['dbi']->tryQueryAsControlUser($sql_query); if ($result) { $value = $result->fetchValue(); if (is_string($value)) { return json_decode($value, true); } } return []; } /** * Save recent/favorite tables into phpMyAdmin database. * * @return true|Message */ public function saveToDb() { $username = $GLOBALS['cfg']['Server']['user']; $sql_query = ' REPLACE INTO ' . $this->getPmaTable() . ' (`username`, `tables`)' . " VALUES ('" . $GLOBALS['dbi']->escapeString($username) . "', '" . $GLOBALS['dbi']->escapeString( json_encode($this->tables) ) . "')"; $success = $GLOBALS['dbi']->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL); if (! $success) { $error_msg = ''; switch ($this->tableType) { case 'recent': $error_msg = __('Could not save recent table!'); break; case 'favorite': $error_msg = __('Could not save favorite table!'); break; } $message = Message::error($error_msg); $message->addMessage( Message::rawError($GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL)), '

' ); return $message; } return true; } /** * Trim recent.favorite table according to the * NumRecentTables/NumFavoriteTables configuration. */ public function trim(): bool { $max = max( $GLOBALS['cfg']['Num' . ucfirst($this->tableType) . 'Tables'], 0 ); $trimmingOccurred = count($this->tables) > $max; while (count($this->tables) > $max) { array_pop($this->tables); } return $trimmingOccurred; } /** * Return HTML ul. */ public function getHtmlList(): string { if (count($this->tables)) { if ($this->tableType === 'recent') { $tables = []; foreach ($this->tables as $table) { $tables[] = [ 'db' => $table['db'], 'table' => $table['table'], ]; } return $this->template->render('recent_favorite_table_recent', ['tables' => $tables]); } $tables = []; foreach ($this->tables as $table) { $removeParameters = [ 'db' => $table['db'], 'ajax_request' => true, 'favorite_table' => $table['table'], 'remove_favorite' => true, ]; $tableParameters = [ 'db' => $table['db'], 'table' => $table['table'], 'md5' => md5($table['db'] . '.' . $table['table']), ]; $tables[] = [ 'remove_parameters' => $removeParameters, 'table_parameters' => $tableParameters, ]; } return $this->template->render('recent_favorite_table_favorite', ['tables' => $tables]); } return $this->template->render('recent_favorite_table_no_tables', [ 'is_recent' => $this->tableType === 'recent', ]); } public function getHtml(): string { $html = '
'; if ($this->tableType === 'recent') { $html .= '
'; return $html; } /** * Add recently used or favorite tables. * * @param string $db database name where the table is located * @param string $table table name * * @return true|Message True if success, Message if not */ public function add($db, $table) { // If table does not exist, do not add._getPmaTable() if (! $GLOBALS['dbi']->getColumns($db, $table)) { return true; } $table_arr = []; $table_arr['db'] = $db; $table_arr['table'] = $table; // add only if this is new table if (! isset($this->tables[0]) || $this->tables[0] != $table_arr) { array_unshift($this->tables, $table_arr); $this->tables = array_merge(array_unique($this->tables, SORT_REGULAR)); $this->trim(); if ($this->getPmaTable()) { return $this->saveToDb(); } } return true; } /** * Removes recent/favorite tables that don't exist. * * @param string $db database * @param string $table table * * @return bool|Message True if invalid and removed, False if not invalid, * Message if error while removing */ public function removeIfInvalid($db, $table) { foreach ($this->tables as $tbl) { if ($tbl['db'] != $db || $tbl['table'] != $table) { continue; } // TODO Figure out a better way to find the existence of a table if (! $GLOBALS['dbi']->getColumns($tbl['db'], $tbl['table'])) { return $this->remove($tbl['db'], $tbl['table']); } } return false; } /** * Remove favorite tables. * * @param string $db database name where the table is located * @param string $table table name * * @return true|Message True if success, Message if not */ public function remove($db, $table) { foreach ($this->tables as $key => $value) { if ($value['db'] != $db || $value['table'] != $table) { continue; } unset($this->tables[$key]); } if ($this->getPmaTable()) { return $this->saveToDb(); } return true; } /** * Generate Html for sync Favorite tables anchor. (from localStorage to pmadb) */ public function getHtmlSyncFavoriteTables(): string { $retval = ''; $server_id = $GLOBALS['server']; if ($server_id == 0) { return ''; } $relationParameters = $this->relation->getRelationParameters(); // Not to show this once list is synchronized. if ( $relationParameters->favoriteTablesFeature !== null && ! isset($_SESSION['tmpval']['favorites_synced'][$server_id]) ) { $url = Url::getFromRoute('/database/structure/favorite-table', [ 'ajax_request' => true, 'favorite_table' => true, 'sync_favorite_tables' => true, ]); $retval = ''; } return $retval; } /** * Generate Html to update recent tables. */ public static function getHtmlUpdateRecentTables(): string { return ''; } /** * Return the name of the configuration storage table * * @return string|null pma table name */ private function getPmaTable(): ?string { $relationParameters = $this->relation->getRelationParameters(); if ($this->tableType === 'recent' && $relationParameters->recentlyUsedTablesFeature !== null) { return Util::backquote($relationParameters->recentlyUsedTablesFeature->database) . '.' . Util::backquote($relationParameters->recentlyUsedTablesFeature->recent); } if ($this->tableType === 'favorite' && $relationParameters->favoriteTablesFeature !== null) { return Util::backquote($relationParameters->favoriteTablesFeature->database) . '.' . Util::backquote($relationParameters->favoriteTablesFeature->favorite); } return null; } }