diff --git a/composer.json b/composer.json index 079348ba..b15cab20 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,9 @@ "psr/http-message": "*", "psr/log": "*" }, + "require": { + "php": "^8.1" + }, "require-dev": { "redaxo/php-cs-fixer-config": "^2.0", "friendsofphp/php-cs-fixer": "v3.37.1", diff --git a/docs/09_multiple_db_usage.md b/docs/09_multiple_db_usage.md new file mode 100644 index 00000000..88103a53 --- /dev/null +++ b/docs/09_multiple_db_usage.md @@ -0,0 +1,27 @@ +# Alternative DB aus config.yml nutzen + +> Wenn in der `config.yml` mehrere Datenbankverbindungen eingerichtet sind, lässt sich YForm auch mit diesen +> Datenbanken nutzen. + +## Verfügbarkeit der Funktion + +Ist nur eine Datenbankverbindung in der `config.yml` eingerichteten, werden die Bedienelemente für multiple Datenbanken +nicht angezeigt. Erst wenn mehrere Verbindungen eingerichtet sind, aktivieren sich die Elemente automatisch. + +### Im Migrator + +In der Tabellen-Migration haben alle für die Migration verfügbaren Tabellen ein Prefix mit der Datenbank, in welcher sie +liegen vor ihrem Namen. + +### Beim Erstellen + +Beim Erstellen einer neuen Tabelle über den Table Manager lässt sich die gewünschte Datenbank auswählen. Wird eine +Tabelle im weiteren Verlauf bearbeitet, so wird die Datenbank, in welcher sie gespeichert ist, als Information +angezeigt. + +## ⚠ Wichtige Hinweise + +1. Relationstabellen müssen in derselben Datenbank liegen wie die verknüpfte Tabelle. Es erfolgt **keine + Überprüfung**, ob die Tabelle wirklich in derselben Datenbank liegt. Die Verantwortung dafür liegt beim + Datenbank-Designer, welcher die Relation erstellt. +2. Die Verwaltung der Daten liegt immer in Datenbank 1. diff --git a/lang/de_de.lang b/lang/de_de.lang index 98bb865e..ad70e936 100644 --- a/lang/de_de.lang +++ b/lang/de_de.lang @@ -280,5 +280,4 @@ yform_docs_yorm = YOrm yform_docs_email = E-Mail Templates yform_docs_rest = REST-API yform_docs_tools = Tools - - +yform_docs_multiple_db_usage = Nutzung mehrerer Datenbanken diff --git a/lang/en_gb.lang b/lang/en_gb.lang index 7104bb94..56e64f95 100644 --- a/lang/en_gb.lang +++ b/lang/en_gb.lang @@ -264,4 +264,4 @@ yform_docs_formbuilder = Form builder yform_docs_demos = Demos yform_docs_yorm = Yorm yform_docs_plugins = Plugins - +yform_docs_multiple_db_usage = Use multiple databases diff --git a/lang/es_es.lang b/lang/es_es.lang index d2e8fa24..db3ef0e5 100644 --- a/lang/es_es.lang +++ b/lang/es_es.lang @@ -261,4 +261,4 @@ yform_docs_formbuilder = Formbuilder yform_docs_demos = Demos yform_docs_yorm = Yorm yform_docs_plugins = PlugIns - +yform_docs_multiple_db_usage = Utilizar varias bases de datos diff --git a/lang/pt_br.lang b/lang/pt_br.lang index 4229154a..59606ce9 100644 --- a/lang/pt_br.lang +++ b/lang/pt_br.lang @@ -170,3 +170,5 @@ yform_values_options_boolvalues = Valores Values (0,1 = não selecionado, sele yform_geo_get_position = Obter a localização yform_geo_clear_position = Criar localização + +yform_docs_multiple_db_usage = Utilização de várias bancos de dados diff --git a/lang/sv_se.lang b/lang/sv_se.lang index 525fddcd..ebb71136 100644 --- a/lang/sv_se.lang +++ b/lang/sv_se.lang @@ -267,5 +267,4 @@ yform_docs_yorm = Yorm yform_docs_email = E-Mail mallar yform_docs_rest = REST-API yform_docs_tools = Verktyg - - +yform_docs_multiple_db_usage = Använda flera databaser diff --git a/lib/yform.php b/lib/yform.php index c0e7d841..bf1ed0c4 100644 --- a/lib/yform.php +++ b/lib/yform.php @@ -80,6 +80,7 @@ public function __construct(array $params = []) $this->objparams['main_where'] = ''; // like "id=12" for db $this->objparams['main_id'] = -1; // unique Dataset ID $this->objparams['main_table'] = ''; // for db and unique + $this->objparams['db_id'] = 1; // select alternative database $this->objparams['sql_object'] = null; // rex_sql $this->objparams['form_hiddenfields'] = []; @@ -154,6 +155,20 @@ public function setDebug(bool $s = true): self return $this; } + /** + * Set an alternative database ID. The database with ID $databaseId must be configured and working in core Redaxo + * `config.yml`. + * + * @param int $databaseId + * + * @return $this + */ + public function setDatabaseId(int $databaseId): static + { + $this->objparams['db_id'] = $databaseId; + return $this; + } + public function addPostSaveFunction($callback): self { $this->postSaveFunctions[] = $callback; @@ -294,7 +309,7 @@ public function executeFields(): self // 2. setValue defaults via sql_object if ($this->objparams['getdata']) { if (!$this->objparams['sql_object'] instanceof rex_sql) { - $this->objparams['sql_object'] = rex_sql::factory(); + $this->objparams['sql_object'] = rex_sql::factory($this->objparams['db_id']); $this->objparams['sql_object']->setDebug($this->objparams['debug']); $this->objparams['sql_object']->setQuery('SELECT * from ' . $this->objparams['main_table'] . ' WHERE ' . $this->objparams['main_where']); } @@ -816,4 +831,21 @@ public function hasWarnings(): bool $hasWarningMessages = 0 != count($this->objparams['warning_messages']); return $hasWarnings || $hasWarningMessages; } + + /** + * Return the database configurations from `config.yml`. + * + * @return array + */ + public static function getDatabaseConfigurations() + { + // Only return entries from the db section, that actually contain real data, not empty stubs. + return array_filter( + rex::getProperty('db'), + fn($dbConfig) => !empty($dbConfig['host']) && !empty($dbConfig['login']) + ); + } } diff --git a/lib/yform/action/create_table.php b/lib/yform/action/create_table.php index 3412e4bd..e0d1f96c 100644 --- a/lib/yform/action/create_table.php +++ b/lib/yform/action/create_table.php @@ -12,11 +12,12 @@ class rex_yform_action_create_table extends rex_yform_action_abstract public function executeAction(): void { $table_name = $this->getElement(2); + $db_id = $this->params['db_id'] ?? 1; $table_name = str_replace('%TABLE_PREFIX%', rex::getTablePrefix(), $table_name); $table_exists = false; $cols = []; - $tables = rex_sql::factory()->getArray('show tables'); + $tables = rex_sql::factory($db_id)->getArray('show tables'); foreach ($tables as $table) { if (current($table) == $table_name) { $table_exists = true; @@ -25,16 +26,16 @@ public function executeAction(): void } if (!$table_exists) { - rex_sql::factory()->setQuery('CREATE TABLE `' . $table_name . '` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;'); + rex_sql::factory($db_id)->setQuery('CREATE TABLE `' . $table_name . '` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;'); } - foreach (rex_sql::factory()->getArray('show columns from ' . $table_name) as $k => $v) { + foreach (rex_sql::factory($db_id)->getArray('show columns from ' . $table_name) as $k => $v) { $cols[] = $v['Field']; } foreach ($this->params['value_pool']['sql'] as $key => $value) { if (!in_array($key, $cols)) { - rex_sql::factory()->setQuery('ALTER TABLE `' . $table_name . '` ADD `' . $key . '` TEXT NOT NULL;'); + rex_sql::factory($db_id)->setQuery('ALTER TABLE `' . $table_name . '` ADD `' . $key . '` TEXT NOT NULL;'); } } } diff --git a/lib/yform/action/db.php b/lib/yform/action/db.php index 26068959..701664da 100644 --- a/lib/yform/action/db.php +++ b/lib/yform/action/db.php @@ -12,7 +12,8 @@ class rex_yform_action_db extends rex_yform_action_abstract { public function executeAction(): void { - $sql = rex_sql::factory(); + $db_id = $this->params['db_id'] ?? 1; + $sql = rex_sql::factory($db_id); $sql->setDebug($this->params['debug']); if (!$main_table = $this->getElement(2)) { @@ -56,7 +57,7 @@ public function executeAction(): void $action = 'update'; if ($this->params['main_id'] <= 0) { - $sql_id = rex_sql::factory(); + $sql_id = rex_sql::factory($db_id); $sql_id->setTable($main_table); $sql_id->setWhere($where); $sql_id->select('id'); diff --git a/lib/yform/action/db_query.php b/lib/yform/action/db_query.php index 8765151b..96e90b77 100644 --- a/lib/yform/action/db_query.php +++ b/lib/yform/action/db_query.php @@ -11,6 +11,7 @@ class rex_yform_action_db_query extends rex_yform_action_abstract { public function executeAction(): void { + $db_id = $this->params['db_id'] ?? 1; $query = trim($this->getElement(2)); $labels = explode(',', $this->getElement(3)); @@ -22,7 +23,7 @@ public function executeAction(): void } try { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($db_id); $sql->setDebug($this->params['debug']); $params = []; diff --git a/lib/yform/action/readtable.php b/lib/yform/action/readtable.php index 6c6db2a3..364f3ba5 100644 --- a/lib/yform/action/readtable.php +++ b/lib/yform/action/readtable.php @@ -11,12 +11,13 @@ class rex_yform_action_readtable extends rex_yform_action_abstract { public function executeAction(): void { + $db_id = $this->params['db_id'] ?? 1; if (!isset($this->params['value_pool']['email'][$this->getElement(4)])) { return; } $value = $this->params['value_pool']['email'][$this->getElement(4)]; - $gd = rex_sql::factory(); + $gd = rex_sql::factory($db_id); if ($this->params['debug']) { $gd->setDebug(); } diff --git a/lib/yform/validate/in_table.php b/lib/yform/validate/in_table.php index e81841f8..0bfd2ce9 100644 --- a/lib/yform/validate/in_table.php +++ b/lib/yform/validate/in_table.php @@ -11,10 +11,12 @@ class rex_yform_validate_in_table extends rex_yform_validate_abstract { public function enterObject() { - $db = rex_sql::factory(); + $table = $this->getElement(3); + $db_id = $this->params['db_id'] ?? 1; + + $db = rex_sql::factory($db_id); $db->setDebug($this->params['debug']); - $table = $this->getElement(3); $labels = $this->getElement(2); $fields = $this->getElement(4); diff --git a/lib/yform/validate/unique.inc.php b/lib/yform/validate/unique.inc.php index b64a7e65..f0940e11 100644 --- a/lib/yform/validate/unique.inc.php +++ b/lib/yform/validate/unique.inc.php @@ -11,7 +11,8 @@ class rex_yform_validate_unique extends rex_yform_validate_abstract { public function enterObject() { - $cd = rex_sql::factory(); + $db_id = $this->params['db_id'] ?? 1; + $cd = rex_sql::factory($db_id); $table = $this->params['main_table']; if ('' != $this->getElement('table')) { diff --git a/lib/yform/value/choice.php b/lib/yform/value/choice.php index cb23bcd5..a827dc30 100644 --- a/lib/yform/value/choice.php +++ b/lib/yform/value/choice.php @@ -285,6 +285,7 @@ public static function getSearchFilter($params) private static function createChoiceList($elements) { $self = new self(); + $db_id = $self->params['db_id'] ?? 1; $options = [ 'choices' => [], @@ -324,7 +325,7 @@ private static function createChoiceList($elements) $choiceList = new rex_yform_choice_list($options); if (is_string($choicesElement) && 'SELECT' == rex_sql::getQueryType($choicesElement)) { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($db_id); $sql->setDebug($self->getParam('debug')); $choiceList->createListFromSqlArray( $sql->getArray($choicesElement), diff --git a/lib/yform/value/index.php b/lib/yform/value/index.php index 5b14b26e..4e41ad84 100644 --- a/lib/yform/value/index.php +++ b/lib/yform/value/index.php @@ -110,7 +110,7 @@ private function addRelation(array &$relations, array $names) private function getRelationValues(array $relations) { $table = rex_yform_manager_table::get($this->params['main_table']); - $sql = rex_sql::factory(); + $sql = rex_sql::factory($table->getDatabaseId()); $sql->setDebug($this->params['debug']); foreach ($relations as $name => $sub) { diff --git a/plugins/manager/fragments/yform/manager/page/list.php b/plugins/manager/fragments/yform/manager/page/list.php index 3566e060..bbdaf8d3 100644 --- a/plugins/manager/fragments/yform/manager/page/list.php +++ b/plugins/manager/fragments/yform/manager/page/list.php @@ -14,7 +14,7 @@ $hasDataPageFunctions = $this->getVar('hasDataPageFunctions'); /** @var rex_yform_list $list */ -$list = rex_yform_list::factory($query, $table->getListAmount()); +$list = rex_yform_list::factory($query, $table->getListAmount(), db: $table->getDatabaseId()); $list->addTableAttribute('class', 'table-striped table-hover yform-table-' . rex_string::normalize($this->table->getTableName())); diff --git a/plugins/manager/install.php b/plugins/manager/install.php index 7709796f..17ec9325 100644 --- a/plugins/manager/install.php +++ b/plugins/manager/install.php @@ -21,6 +21,7 @@ ->ensurePrimaryIdColumn() ->ensureColumn(new rex_sql_column('status', 'tinyint(1)')) ->ensureColumn(new rex_sql_column('table_name', 'varchar(191)')) + ->ensureColumn(new rex_sql_column('db_id', 'tinyint unsigned', false, 1)) ->ensureColumn(new rex_sql_column('name', 'varchar(191)')) ->ensureColumn(new rex_sql_column('description', 'text')) ->ensureColumn(new rex_sql_column('list_amount', 'int(11)', false, '50')) diff --git a/plugins/manager/lang/de_de.lang b/plugins/manager/lang/de_de.lang index 9fd0f29c..5ec4e17c 100644 --- a/plugins/manager/lang/de_de.lang +++ b/plugins/manager/lang/de_de.lang @@ -58,6 +58,7 @@ yform_manager_table_enter_name = Bitte tragen Sie die Tabellenbezeichnung ein yform_manager_table_enter_specialchars = Bitte tragen Sie beim Tabellenname nur Kleinbuchstaben und Zahlen ein. Das erste Zeichen muss ein Buchstabe sein yform_manager_table_exists = Dieser Tabellenname ist bereits vorhanden +yform_manager_database_selection = Datenbank yform_manager_table_prio = Priorität yform_manager_table_prio_short = Prio yform_manager_table_name = Name diff --git a/plugins/manager/lang/en_gb.lang b/plugins/manager/lang/en_gb.lang index 468e7df9..db87d74f 100644 --- a/plugins/manager/lang/en_gb.lang +++ b/plugins/manager/lang/en_gb.lang @@ -56,6 +56,7 @@ yform_manager_table_enter_name = Please enter table name yform_manager_table_enter_specialchars = Please enter only letters and numbers for the table name. The first character must be a letter yform_manager_table_exists = This table name already exists +yform_manager_database_selection = Database yform_manager_table_prio = Priority yform_manager_table_prio_short = Prio yform_manager_table_name = Name diff --git a/plugins/manager/lang/es_es.lang b/plugins/manager/lang/es_es.lang index 3e2bc382..34dbc2f4 100644 --- a/plugins/manager/lang/es_es.lang +++ b/plugins/manager/lang/es_es.lang @@ -56,6 +56,7 @@ yform_manager_table_enter_name = Por favor ingrese el nombre de la tabla yform_manager_table_enter_specialchars = Por favor ingrese solo letras y números para el nombre de la tabla. El primer personaje debe ser una letra yform_manager_table_exists = Este nombre de tabla ya existe +yform_manager_database_selection = Base de datos yform_manager_table_prio = Prioridad yform_manager_table_prio_short = Prio yform_manager_table_name = Nombre diff --git a/plugins/manager/lang/pt_br.lang b/plugins/manager/lang/pt_br.lang index 460d00bc..59752678 100644 --- a/plugins/manager/lang/pt_br.lang +++ b/plugins/manager/lang/pt_br.lang @@ -52,6 +52,7 @@ yform_manager_table_enter_name = Por favor, insira um nome para a tabela yform_manager_table_enter_specialchars = Por favor, insira somente letras e números no nome da tabela. O primeiro caractere deve ser uma letra. yform_manager_table_exists = Esse noem já existe. +yform_manager_database_selection = Bankco de dados yform_manager_table_prio = Prioridade yform_manager_table_prio_short = Prio yform_manager_table_name = Nome diff --git a/plugins/manager/lang/sv_se.lang b/plugins/manager/lang/sv_se.lang index 625e2f5b..86f82d84 100644 --- a/plugins/manager/lang/sv_se.lang +++ b/plugins/manager/lang/sv_se.lang @@ -56,6 +56,7 @@ yform_manager_table_enter_name = Var god ange tabellnamnet yform_manager_table_enter_specialchars = Var god ange endast bokstäver och siffror vid tabellnamnet. Första tecknet måste vara en bokstav. yform_manager_table_exists = Tabellnamnet finns redan +yform_manager_database_selection = Databas yform_manager_table_prio = Prioritet yform_manager_table_prio_short = Prio yform_manager_table_name = Namn diff --git a/plugins/manager/lib/yform/action/manage_db.php b/plugins/manager/lib/yform/action/manage_db.php index d9c54f5a..5396621f 100644 --- a/plugins/manager/lib/yform/action/manage_db.php +++ b/plugins/manager/lib/yform/action/manage_db.php @@ -25,8 +25,6 @@ public function executeAction(): void // ********************************* TABLE A // $this->params["debug"]= TRUE; - $sql = rex_sql::factory(); - $sql->setDebug($this->params['debug']); $main_table = ''; if ('' != $this->getElement(2)) { @@ -34,6 +32,10 @@ public function executeAction(): void } else { $main_table = $this->params['main_table']; } + $db_id = $this->params['db_id'] ?? 1; + $sql = rex_sql::factory($db_id); + $sql->setDebug($this->params['debug']); + if ('' == $main_table) { $this->params['form_show'] = true; diff --git a/plugins/manager/lib/yform/manager.php b/plugins/manager/lib/yform/manager.php index e1061f3f..b9524cee 100644 --- a/plugins/manager/lib/yform/manager.php +++ b/plugins/manager/lib/yform/manager.php @@ -1426,7 +1426,8 @@ public static function checkField($l, $v, $p) public function createTable($mifix, $data_table, $params = [], $debug = false) { // Tabelle erstellen wenn noch nicht vorhanden - $c = rex_sql::factory(); + $db_id = rex_yform_manager_table::get($data_table)->getDatabaseId(); + $c = rex_sql::factory($db_id); $c->setDebug($debug); $c->setQuery('CREATE TABLE IF NOT EXISTS `' . $data_table . '` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;'); diff --git a/plugins/manager/lib/yform/manager/dataset.php b/plugins/manager/lib/yform/manager/dataset.php index aca1e623..dc8f26b8 100644 --- a/plugins/manager/lib/yform/manager/dataset.php +++ b/plugins/manager/lib/yform/manager/dataset.php @@ -161,7 +161,8 @@ public static function queryOne(string $query, array $params = [], ?string $tabl return $class::queryOne($query, $params, $table); } - $sql = rex_sql::factory(); + $db_id = rex_yform_manager_table::get($table)->getDatabaseId(); + $sql = rex_sql::factory($db_id); $sql ->setDebug(self::$debug) ->setQuery($query, $params); @@ -191,7 +192,8 @@ public static function queryCollection(string $query, array $params = [], ?strin return $class::queryCollection($query, $params, $table); } - $sql = rex_sql::factory(); + $db_id = rex_yform_manager_table::get($table)->getDatabaseId(); + $sql = rex_sql::factory($db_id); $sql->setDebug(self::$debug); $data = $sql->getArray($query, $params); @@ -301,7 +303,7 @@ public function getData(): array public function loadData(): void { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->getTable()->getDatabaseId()); $rows = $sql->getArray('SELECT * FROM `' . $this->table . '` WHERE id = ? LIMIT 1', [$this->id]); $this->exists = isset($rows[0]); if ($this->exists) { @@ -463,7 +465,7 @@ public function delete(): bool $this->makeSnapshot(self::ACTION_DELETE); } - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->getTable()->getDatabaseId()); $sql ->setDebug(self::$debug) ->setTable($this->table) @@ -572,19 +574,20 @@ public function makeSnapshot(string $action): void // ep to overwrite user $user = rex_extension::registerPoint(new rex_extension_point('YCOM_HISTORY_USER', $user)); - $sql = rex_sql::factory(); - $sql->setDebug(self::$debug); - $sql + $historySql = rex_sql::factory(); + $historySql->setDebug(self::$debug); + $historySql ->setTable(rex::getTable('yform_history')) ->setValue('table_name', $this->table) ->setValue('dataset_id', $this->id) ->setValue('action', $action) ->setValue('user', $user) - ->setValue('timestamp', $sql::datetime()) + ->setValue('timestamp', $historySql::datetime()) ->insert(); - $historyId = $sql->getLastId(); + $historyId = $historySql->getLastId(); + $sql = rex_sql::factory($this->getTable()->getDatabaseId()); $sql ->setTable($this->table) ->setWhere(['id' => $this->id]) @@ -619,7 +622,7 @@ public function makeSnapshot(string $action): void } } - $sql->setQuery('INSERT INTO ' . rex::getTable('yform_history_field') . ' (`history_id`, `field`, `value`) VALUES ' . implode(', ', $inserts)); + $historySql->setQuery('INSERT INTO ' . rex::getTable('yform_history_field') . ' (`history_id`, `field`, `value`) VALUES ' . implode(', ', $inserts)); } public function restoreSnapshot(int $snapshotId): bool @@ -681,6 +684,7 @@ private function getInternalForm(): rex_yform $yform->setObjectparams('form_needs_output', false); $yform->setObjectparams('csrf_protection', false); $yform->setObjectparams('get_field_type', ''); + $yform->setObjectparams('db_id', $this->getTable()->getDatabaseId()); return $yform; } @@ -716,6 +720,7 @@ private function createForm(): rex_yform } $yform->setObjectparams('main_table', $this->table); + $yform->setObjectparams('db_id', $this->getTable()->getDatabaseId()); $yform->setActionField('db', [$this->table, 'main_where']); return $yform; diff --git a/plugins/manager/lib/yform/manager/query.php b/plugins/manager/lib/yform/manager/query.php index 466c895e..fa0c15fa 100644 --- a/plugins/manager/lib/yform/manager/query.php +++ b/plugins/manager/lib/yform/manager/query.php @@ -731,7 +731,7 @@ public function findValueRaw(string $expression) ->selectRaw($expression, 'value') ->limit(1); - $sql = rex_sql::factory(); + $sql = rex_sql::factory($query->getTable()->getDatabaseId()); $sql->setQuery($query->getQuery(), $query->getParams()); return $sql->getRows() ? $sql->getValue('value') : null; @@ -761,7 +761,7 @@ public function findValuesRaw(string $expression, ?string $keyColumn = null): ar $query->select($keyColumn); } - $sql = rex_sql::factory(); + $sql = rex_sql::factory($query->getTable()->getDatabaseId()); $array = $sql->getArray($query->getQuery(), $query->getParams()); return array_column($array, 'value', $keyColumn); @@ -775,7 +775,7 @@ public function count(): int ->selectRaw('COUNT(*)', 'count') ->resetOrderBy(); - $sql = rex_sql::factory(); + $sql = rex_sql::factory($query->getTable()->getDatabaseId()); $sql->setQuery($query->getQuery(), $query->getParams()); return (int) $sql->getValue('count'); @@ -790,7 +790,7 @@ public function exists(): bool ->resetOrderBy() ->limit(1); - $sql = rex_sql::factory(); + $sql = rex_sql::factory($query->getTable()->getDatabaseId()); $sql->setQuery($query->getQuery(), $query->getParams()); return $sql->getRows() > 0; diff --git a/plugins/manager/lib/yform/manager/table.php b/plugins/manager/lib/yform/manager/table.php index 0d528ffb..f79606a3 100644 --- a/plugins/manager/lib/yform/manager/table.php +++ b/plugins/manager/lib/yform/manager/table.php @@ -35,8 +35,8 @@ private function __construct(array $data) { $this->values = $data['table']; $this->columns = $data['columns']; - $this->relatedTableNames = $data['related_tables']; - $this->fieldValues = $data['fields']; + $this->relatedTableNames = $data['related_tables'] ?? []; + $this->fieldValues = $data['fields'] ?? []; } public static function setTableLayout(string $tableName, string $path): void @@ -53,6 +53,16 @@ public function getTableLayout(): string return $tableLayout; } + /** + * Returns the ID of the database where this table is saved. Database ID must be configured in `config.yml`. + * + * @return int + */ + public function getDatabaseId(): int + { + return $this->values['db_id'] ?? 1; + } + /** * @param string $tableName * @@ -159,7 +169,7 @@ public function getId() public function hasId(): bool { - $columns = rex_sql::showColumns($this->getTableName()); + $columns = rex_sql::showColumns($this->getTableName(), $this->getDatabaseId()); foreach ($columns as $column) { if ('id' == $column['name'] && 'auto_increment' == $column['extra']) { return true; @@ -380,7 +390,7 @@ public function toArray() public function removeRelationTableRelicts() { - $deleteSql = rex_sql::factory(); + $deleteSql = rex_sql::factory($this->getDatabaseId()); foreach ($this->getValueFields(['type_name' => 'be_manager_relation']) as $field) { if ($field->getElement('relation_table')) { $table = self::get($field->getElement('relation_table')); @@ -398,7 +408,7 @@ public function removeRelationTableRelicts() public static function getMaximumTablePrio() { - $sql = 'select max(prio) as prio from ' . self::table() . ''; + $sql = 'select max(prio) as prio from ' . self::table(); $gf = rex_sql::factory(); if (self::$debug) { $gf->setDebug(); @@ -519,7 +529,8 @@ private static function getCache(): mixed self::$cache[$tableName]['table'] = $table; self::$cache[$tableName]['columns'] = []; try { - foreach (rex_sql::showColumns($tableName) as $column) { + $tableDbId = static::get($tableName)->getDatabaseId(); + foreach (rex_sql::showColumns($tableName, $tableDbId) as $column) { if ('id' !== $column['name']) { self::$cache[$tableName]['columns'][$column['name']] = $column; } diff --git a/plugins/manager/lib/yform/manager/table/api.php b/plugins/manager/lib/yform/manager/table/api.php index 26c27fe2..48e39780 100644 --- a/plugins/manager/lib/yform/manager/table/api.php +++ b/plugins/manager/lib/yform/manager/table/api.php @@ -27,6 +27,7 @@ public static function setTable(array $table, array $table_fields = []): ?rex_yf $table_insert->setDebug(self::$debug); $table_insert->setTable(rex_yform_manager_table::table()); $table_insert->setValue('table_name', $table_name); + $table_insert->setValue('db_id', $table['db_id'] ?? 1); if (!isset($table['name']) || '' == $table['name']) { $table['name'] = $table['table_name']; @@ -245,9 +246,9 @@ public static function removeTablefield(string $table_name, string $field_name): /** * @throws rex_sql_exception */ - public static function migrateTable(string $table_name, bool $schema_overwrite = false): void + public static function migrateTable(string $table_name, bool $schema_overwrite = false, int $db_id = 1): void { - $columns = rex_sql::showColumns($table_name); + $columns = rex_sql::showColumns($table_name, $db_id); if (0 == count($columns)) { throw new Exception('`' . $table_name . '` does not exists or no fields available'); @@ -257,6 +258,7 @@ public static function migrateTable(string $table_name, bool $schema_overwrite = 'table_name' => $table_name, 'status' => 1, 'schema_overwrite' => $schema_overwrite ? 1 : 0, + 'db_id' => $db_id, ]; $error = true; @@ -393,7 +395,8 @@ public static function migrateField(string $table_name, array $column): array case 'tinyint': if (1 == $column['length']) { - $sql = rex_sql::factory(); + $db_id = rex_yform_manager_table::get($table_name)->getDatabaseId(); + $sql = rex_sql::factory($db_id); $sql->setQuery('SELECT * FROM ' . $sql->escapeIdentifier($table_name) . ' WHERE ' . $sql->escapeIdentifier($column['name']) . ' NOT IN (0, 1) LIMIT 1'); if (!$sql->getRows()) { $fields[] = [ @@ -562,7 +565,7 @@ public static function generateTableAndFields(rex_yform_manager_table $table, bo return; } - $c = rex_sql::factory(); + $c = rex_sql::factory($table->getDatabaseId()); $c->setDebug(self::$debug); $c->setQuery('CREATE TABLE IF NOT EXISTS `' . $table->getTableName() . '` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;'); @@ -573,7 +576,7 @@ public static function generateTableAndFields(rex_yform_manager_table $table, bo // remember fields, create and in case delete $savedColumns = $table->getColumns(); - $EnsureTable = rex_sql_table::get($table->getTableName()); + $EnsureTable = rex_sql_table::get($table->getTableName(), $table->getDatabaseId()); $EnsureTable ->ensurePrimaryIdColumn(); diff --git a/plugins/manager/lib/yform/value/be_link.php b/plugins/manager/lib/yform/value/be_link.php index b035f405..c6f87fc9 100644 --- a/plugins/manager/lib/yform/value/be_link.php +++ b/plugins/manager/lib/yform/value/be_link.php @@ -99,7 +99,9 @@ public static function isArticleInUse(rex_extension_point $ep) } $messages = ''; foreach ($tables as $tableName => $conditions) { - $items = $sql->getArray('SELECT `id` FROM ' . $tableName . ' WHERE ' . implode(' OR ', $conditions)); + $databaseId = rex_yform_manager_table::get($tableName)?->getDatabaseId() ?? 1; + $tableSql = rex_sql::factory($databaseId); + $items = $tableSql->getArray('SELECT `id` FROM ' . $tableName . ' WHERE '.implode(' OR ', $conditions)); if (count($items)) { foreach ($items as $item) { $sqlData = \rex_sql::factory(); diff --git a/plugins/manager/lib/yform/value/be_manager_relation.php b/plugins/manager/lib/yform/value/be_manager_relation.php index e6af2a6c..6a3f7145 100644 --- a/plugins/manager/lib/yform/value/be_manager_relation.php +++ b/plugins/manager/lib/yform/value/be_manager_relation.php @@ -459,7 +459,8 @@ public function postSave(): void $values = array_map('intval', $values); - $sql = rex_sql::factory(); + $databaseId = rex_yform_manager_table::get($relationTable)->getDatabaseId(); + $sql = rex_sql::factory($databaseId); $sql->setDebug($this->params['debug']); $relationTablePreEditValues = $this->getRelationTableValues(); foreach ($values as $value) { @@ -553,7 +554,8 @@ public static function getListValue($params) $relationTableFields = self::getRelationTableFieldsForTables($field['table_name'], $field['relation_table'], $field['table']); if (isset($relationTableFields['source']) && '' != $relationTableFields['source'] && isset($relationTableFields['target']) && '' != $relationTableFields['target']) { - $sql = rex_sql::factory(); + $databaseId = rex_yform_manager_table::get($field['relation_table'])->getDatabaseId(); + $sql = rex_sql::factory($databaseId); $sql->setQuery( ' SELECT ' . $sql->escapeIdentifier($relationTableFields['target']) . ' as id @@ -599,7 +601,7 @@ public static function getListValues($table, $field, array $filter = []) if (!isset(self::$yform_list_values[$table][$field][$filterHash])) { $tableObject = rex_yform_manager_table::get($table); self::$yform_list_values[$table][$field][$filterHash] = []; - $db = rex_sql::factory(); + $db = rex_sql::factory($tableObject->getDatabaseId()); // $db->setDebug(); $where = ''; $join = ''; @@ -707,7 +709,8 @@ private static function getFilterArray($rawFilter, $table, callable $getValueFor $relation = rex_yform_manager_table::get($table)->getRelation($value[0]); $value[0] = $getValueForKey($value[0]); if ($value[0] && $relation) { - $relationSql = rex_sql::factory(); + $databaseId = rex_yform_manager_table::get($relation['table'])->getDatabaseId(); + $relationSql = rex_sql::factory($databaseId); // $relationSql->debugsql = true; $tables = '' . $relationSql->escapeIdentifier($relation['table']) . ' t0'; for ($i = 1; $i < count($value) - 1; ++$i) { @@ -764,7 +767,8 @@ protected function getRelationTableValues() $values = []; $relationTableFields = $this->getRelationTableFields(); if ($relationTableFields['source'] && $relationTableFields['target']) { - $sql = rex_sql::factory(); + $databaseId = rex_yform_manager_table::get($this->getElement('relation_table'))->getDatabaseId(); + $sql = rex_sql::factory($databaseId); $sql->setDebug($this->params['debug']); $sql->setQuery( ' @@ -838,7 +842,7 @@ public static function getSearchFilter($params) /** @var rex_yform_manager_field $field */ $field = $params['field']; - $sql = rex_sql::factory(); + $sql = rex_sql::factory($query->getTable()->getDatabaseId()); if (!$field->getElement('relation_table')) { return $query->whereListContains($query->getTableAlias() . '.' . $field->getName(), $values); diff --git a/plugins/manager/lib/yform/value/be_media.php b/plugins/manager/lib/yform/value/be_media.php index 2b5f8f11..2e2ecf40 100644 --- a/plugins/manager/lib/yform/value/be_media.php +++ b/plugins/manager/lib/yform/value/be_media.php @@ -141,7 +141,9 @@ public static function isMediaInUse(rex_extension_point $ep) $messages = ''; foreach ($tables as $tableName => $conditions) { - $items = $sql->getArray('SELECT `id` FROM ' . $tableName . ' WHERE ' . implode(' OR ', $conditions)); + $databaseId = rex_yform_manager_table::get($tableName)->getDatabaseId(); + $mediaSql = rex_sql::factory($databaseId); + $items = $mediaSql->getArray('SELECT `id` FROM ' . $tableName . ' WHERE ' . implode(' OR ', $conditions)); if (count($items)) { foreach ($items as $item) { $sqlData = \rex_sql::factory(); diff --git a/plugins/manager/lib/yform/value/prio.php b/plugins/manager/lib/yform/value/prio.php index 3a591d86..5c9202c0 100644 --- a/plugins/manager/lib/yform/value/prio.php +++ b/plugins/manager/lib/yform/value/prio.php @@ -21,7 +21,7 @@ public function enterObject() $options[''] = rex_i18n::msg('yform_prio_bottom'); } else { $this->preEditScopeWhere = $scopeWhere; - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->params['db_id']); if ($this->debug) { $sql->setDebug(); } @@ -113,7 +113,7 @@ public function getDefinitions(): array public function postAction(): void { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->params['db_id']); if ($this->debug) { $sql->setDebug(); } @@ -139,7 +139,7 @@ public function postAction(): void protected function getScopeWhere() { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->params['db_id']); $scope = $this->getElement('scope'); if (!is_array($scope) && $scope) { $scope = array_filter(explode(',', $scope)); @@ -154,7 +154,7 @@ protected function getScopeWhere() } elseif (isset($this->params['sql_object']) && $this->params['sql_object']->hasValue($column)) { $value = $this->params['sql_object']->getValue($column); } elseif ($this->params['main_id'] > 0) { - $sql = rex_sql::factory(); + $sql = rex_sql::factory($this->params['db_id']); if ($this->debug) { $sql->setDebug(); } diff --git a/plugins/manager/pages/data_import.php b/plugins/manager/pages/data_import.php index bcc2ae59..02d49533 100644 --- a/plugins/manager/pages/data_import.php +++ b/plugins/manager/pages/data_import.php @@ -127,9 +127,7 @@ break; } if (2 == $missing_columns) { - $i = rex_sql::factory(); - - foreach ($mc as $mcc) { + foreach ($mc as $mcc) { rex_sql::factory() ->setTable(rex_yform_manager_field::table()) ->setValue('table_name', $this->table->getTablename()) diff --git a/plugins/manager/pages/table_edit.php b/plugins/manager/pages/table_edit.php index ef983a83..4a2d9248 100644 --- a/plugins/manager/pages/table_edit.php +++ b/plugins/manager/pages/table_edit.php @@ -7,6 +7,46 @@ * @author www.yakamara.de */ +/** + * Add a database selection choice to $form if $fieldEnabled is true, show the configured database from $table by + * adding a hidden and a show value field to $form if $fieldEnabled is false. + * + * @param rex_yform $form Form to add the select field to. + * @param array $dbConfig) { + $databaseChoices[$dbId] = "DB {$dbId}: Host »{$dbConfig['host']}«"; + } + + if (true !== $fieldEnabled) { + $form->setHiddenField('db_id', $table->getDatabaseId()); + $form->setValueField('showvalue', [ + 'db_id', + rex_i18n::msg('yform_manager_database_selection'), + 1, + $databaseChoices[$table->getDatabaseId()], + ]); + } else { + $form->setValueField('choice', [ + 'name' => 'db_id', + 'label' => rex_i18n::msg('yform_manager_database_selection'), + 'choices' => $databaseChoices, + ]); + } +} + echo rex_view::title(rex_i18n::msg('yform')); $_csrf_key = 'yform_table_edit'; @@ -66,6 +106,7 @@ } } elseif (('add' == $func || 'edit' == $func) && rex::getUser()->isAdmin()) { $table = null; + $dbConfigs = rex_yform::getDatabaseConfigurations(); if ('edit' == $func) { $table = rex_yform_manager_table::getById($table_id); if (!$table) { @@ -90,6 +131,9 @@ $yform->setValueField('html', ['html' => '
']); $yform->setValueField('html', ['html' => '']); $yform->setValueField('checkbox', ['status', rex_i18n::msg('yform_tbl_active')]); + if (count($dbConfigs) > 1) { + databaseSelectionChoiceOrShow($yform, $dbConfigs, 'add' === $func, $table); + } $yform->setValueField('prio', ['prio', rex_i18n::msg('yform_manager_table_prio'), 'name']); switch ($func) { diff --git a/plugins/manager/pages/table_migrate.php b/plugins/manager/pages/table_migrate.php index 4b835023..f186f41e 100644 --- a/plugins/manager/pages/table_migrate.php +++ b/plugins/manager/pages/table_migrate.php @@ -12,9 +12,24 @@ $page = rex_request('page', 'string', ''); -$available_tables = rex_sql::factory()->getTablesAndViews(); +$dbConfigs = rex_yform::getDatabaseConfigurations(); +/** @var array $available_tables */ +$available_tables = []; +foreach ($dbConfigs as $dbId => $dbConfig) { + $available_tables = array_merge_recursive( + $available_tables, + array_map( + fn($tableName) => [ + 'db' => $dbId, + 'table' => $tableName, + ], + rex_sql::factory($dbId)->getTablesAndViews() + ) + ); +} $yform_tables = []; +/** @var array $missing_tables */ $missing_tables = []; foreach (rex_yform_manager_table::getAll() as $g_table) { @@ -22,25 +37,39 @@ } foreach ($available_tables as $a_table) { - if (!in_array($a_table, $yform_tables)) { - $missing_tables[$a_table] = $a_table; + if (!in_array($a_table['table'], $yform_tables)) { + $missing_tables[$a_table['table']] = $a_table; } } +$missingTableChoices = []; +$doPrefixDb = count($dbConfigs) > 1; +foreach ($missing_tables as $missingTable) { + $missingTableChoices[$missingTable['table']] = $doPrefixDb + ? "DB{$missingTable['db']}: {$missingTable['table']}" + : $missingTable['table']; +} +asort($missingTableChoices); $yform = new rex_yform(); $yform->setObjectparams('form_showformafterupdate', 1); $yform->setObjectparams('form_name', $_csrf_key); $yform->setHiddenField('page', $page); -$yform->setValueField('choice', ['name' => 'table_name', 'label' => rex_i18n::msg('yform_table'), 'choices' => $missing_tables]); +$yform->setValueField('choice', ['name' => 'table_name', 'label' => rex_i18n::msg('yform_table'), 'choices' => $missingTableChoices]); $yform->setValueField('checkbox', ['schema_overwrite', rex_i18n::msg('yform_manager_table_schema_overwrite')]); $form = $yform->getForm(); if ($yform->objparams['actions_executed']) { $table_name = (string) $yform->objparams['value_pool']['sql']['table_name']; $schema_overwrite = (int) $yform->objparams['value_pool']['sql']['schema_overwrite']; + $selectedTable = array_filter($missing_tables, fn($missingTable) => $missingTable['table'] === $table_name); + $databaseId = array_shift($selectedTable)['db'] ?? 1; try { - rex_yform_manager_table_api::migrateTable($table_name, (0 == $schema_overwrite) ? false : true); // with convert id / auto_increment finder + rex_yform_manager_table_api::migrateTable( + $table_name, + (0 == $schema_overwrite) ? false : true, // with convert id / auto_increment finder + $databaseId + ); echo rex_view::success(rex_i18n::msg('yform_manager_table_migrated_success')); unset($missing_tables[$table_name]); @@ -48,7 +77,7 @@ $yform = new rex_yform(); $yform->setObjectparams('form_showformafterupdate', 1); $yform->setHiddenField('page', $page); - $yform->setValueField('choice', ['name' => 'table_name', 'label' => rex_i18n::msg('yform_table'), 'choices' => $missing_tables]); + $yform->setValueField('choice', ['name' => 'table_name', 'label' => rex_i18n::msg('yform_table'), 'choices' => $missingTableChoices]); $yform->setValueField('checkbox', ['schema_overwrite', rex_i18n::msg('yform_manager_table_schema_overwrite')]); $form = $yform->getForm(); } catch (Exception $e) { diff --git a/tests/rex_yform_yorm_test.php b/tests/rex_yform_yorm_test.php index 3e26951e..fa12a8c0 100644 --- a/tests/rex_yform_yorm_test.php +++ b/tests/rex_yform_yorm_test.php @@ -23,6 +23,7 @@ public static function setUpTable($tableName) $table = rex_yform_manager_table_api::setTable( [ 'table_name' => $tableName, + 'db_id' => 1, 'name' => 'Name of Table - ' . $tableName, 'description' => 'Description of Table - ' . $tableName, 'status' => 1,