Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set locales for all domains when enabling multilingual #17733

Merged
merged 2 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 70 additions & 45 deletions CRM/Core/I18n/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,56 +44,32 @@ public static function dropAllViews() {
* the first locale to create (migrate to).
*/
public static function makeMultilingual($locale) {
$domain = new CRM_Core_DAO_Domain();
$domain->find(TRUE);

// break early if the db is already multi-lang
if ($domain->locales) {
return;
}

$dao = new CRM_Core_DAO();

// build the column-adding SQL queries
$columns = CRM_Core_I18n_SchemaStructure::columns();
$indices = CRM_Core_I18n_SchemaStructure::indices();
$queries = [];
foreach ($columns as $table => $hash) {
// drop old indices
if (isset($indices[$table])) {
foreach ($indices[$table] as $index) {
if (CRM_Core_BAO_SchemaHandler::checkIfIndexExists($table, $index['name'])) {
$queries[] = "DROP INDEX {$index['name']} ON {$table}";
}
}
}
// deal with columns
foreach ($hash as $column => $type) {
$queries[] = "ALTER TABLE {$table} ADD {$column}_{$locale} {$type}";
if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, $column)) {
$queries[] = "UPDATE {$table} SET {$column}_{$locale} = {$column}";
$queries[] = "ALTER TABLE {$table} DROP {$column}";
}
$isUpdateDone = FALSE;
$domain = new CRM_Core_BAO_Domain();
$domain->find();
$domains = [];
while ($domain->fetch()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something is wonky here... I think some cache is being reset as only first is retrieved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - switched to putting in an array first...

// We need to build an array to iterate through here as something later down clears
// the cache on the fetch results & causes only the first to be retrieved.
$domains[] = clone $domain;
}
foreach ($domains as $domain) {
// skip if the domain is already multi-lang.
if ($domain->locales) {
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make sure that all domains have the same locales?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seamuslee001 I dunno - I think one domain could have less than the others but it gets tricky fast. I decided not to change that edge case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colemanw was thinking that instead maybe domain1 should be treated as global domain see other discussion here #17650

}

// add view
$queries[] = self::createViewQuery($locale, $table, $dao);
if (!$isUpdateDone) {
$isUpdateDone = self::alterTablesToSupportMultilingual($locale);
}

// add new indices
$queries = array_merge($queries, array_values(self::createIndexQueries($locale, $table)));
}
// update civicrm_domain.locales
$domain->locales = $locale;
$domain->save();

// execute the queries without i18n rewriting
foreach ($queries as $query) {
$dao->query($query, FALSE);
// CRM-21627 Updates the $dbLocale
CRM_Core_BAO_ConfigSetting::applyLocale(Civi::settings($domain->id), $domain->locales);
}

// update civicrm_domain.locales
$domain->locales = $locale;
$domain->save();

// CRM-21627 Updates the $dbLocale
CRM_Core_BAO_ConfigSetting::applyLocale(Civi::settings($domain->id), $domain->locales);
}

/**
Expand Down Expand Up @@ -606,4 +582,53 @@ public static function triggerInfo(&$info, $tableName = NULL) {
}
}

/**
* Alter tables to the structure to support multilingual.
*
* This alters the db structure to use language specific field names for
* localised fields and adds the relevant views.
*
* @param string $locale
*
* @return bool
*/
protected static function alterTablesToSupportMultilingual($locale): bool {
$dao = new CRM_Core_DAO();

// build the column-adding SQL queries
$columns = CRM_Core_I18n_SchemaStructure::columns();
$indices = CRM_Core_I18n_SchemaStructure::indices();
$queries = [];
foreach ($columns as $table => $hash) {
// drop old indices
if (isset($indices[$table])) {
foreach ($indices[$table] as $index) {
if (CRM_Core_BAO_SchemaHandler::checkIfIndexExists($table, $index['name'])) {
$queries[] = "DROP INDEX {$index['name']} ON {$table}";
}
}
}
// deal with columns
foreach ($hash as $column => $type) {
$queries[] = "ALTER TABLE {$table} ADD {$column}_{$locale} {$type}";
if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, $column)) {
$queries[] = "UPDATE {$table} SET {$column}_{$locale} = {$column}";
$queries[] = "ALTER TABLE {$table} DROP {$column}";
}
}

// add view
$queries[] = self::createViewQuery($locale, $table, $dao);

// add new indices
$queries = array_merge($queries, array_values(self::createIndexQueries($locale, $table)));
}

// execute the queries without i18n rewriting
foreach ($queries as $query) {
$dao->query($query, FALSE);
}
return TRUE;
}

}
8 changes: 8 additions & 0 deletions tests/phpunit/CRM/Core/I18n/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ public function tearDown() {
* @param string $expectedRewrite
*
* @dataProvider translateTables
* @throws \CRM_Core_Exception
*/
public function testI18nSchemaRewrite($table, $expectedRewrite) {
CRM_Core_I18n_Schema::makeMultilingual('en_US');
$domains = $this->callAPISuccess('Domain', 'get')['values'];
foreach ($domains as $domain) {
seamuslee001 marked this conversation as resolved.
Show resolved Hide resolved
// If the DB is multilingual the locales value must be not-null for all domains
// to ensure the db can be accessed (I suspect it must be the same for all locales but
// if null then the database layer attempts to access non-existent fields 'label' not label_en_us'.
$this->assertEquals('en_US', $domain['locales']);
}
$skip_tests = FALSE;
if (in_array($table, ['civicrm_option_group', 'civicrm_event'])) {
$skip_tests = TRUE;
Expand Down