string('locale', 14)->change(); }); } if (empty($this->CONTEXT_TABLE) || empty($this->CONTEXT_SETTINGS_TABLE) || empty($this->CONTEXT_COLUMN)) { throw new Exception('Upgrade could not be completed because required properties for the MergeLocalesMigration migration are undefined.'); } // All _settings tables. foreach ($this->getSettingsTables() as $tableName => [$entityIdColumnName, $primaryKeyColumnName]) { if (!Schema::hasTable($tableName) || !Schema::hasColumn($tableName, 'locale')) { continue; } foreach (self::getAffectedLocales() as $source => $target) { DB::table($tableName) ->where('locale', $source) ->update(['locale' => $target]); } } // Tables // site $site = DB::table('site') ->select(['supported_locales', 'installed_locales', 'primary_locale']) ->first(); $this->updateArrayLocaleNoId($site->supported_locales, 'site', 'supported_locales'); $this->updateArrayLocaleNoId($site->installed_locales, 'site', 'installed_locales'); $this->updateSingleValueLocaleNoId($site->primary_locale, 'site', 'primary_locale'); Schema::table('site', function (Blueprint $table) { $table->string('installed_locales')->default('en')->change(); }); // users $migration = $this; $users = DB::table('users')->chunkById(1000, function ($users) use ($migration) { foreach ($users as $user) { $migration->updateArrayLocale($user->locales, 'users', 'locales', 'user_id', $user->user_id); } }, 'user_id'); // submissions $submissions = DB::table('submissions')->chunkById(1000, function ($submissions) use ($migration) { foreach ($submissions as $submission) { $migration->updateSingleValueLocale($submission->locale, 'submissions', 'locale', 'submission_id', $submission->submission_id); } }, 'submission_id'); // email_templates_default_data $emailTemplatesDefaultData = DB::table('email_templates_default_data') ->get(); foreach ($emailTemplatesDefaultData as $emailTemplatesDefaultDataCurrent) { $this->updateSingleValueLocaleEmailData($emailTemplatesDefaultDataCurrent->locale, 'email_templates_default_data', $emailTemplatesDefaultDataCurrent->email_key, $emailTemplatesDefaultData); } Schema::table('email_templates_default_data', function (Blueprint $table) { $table->string('locale')->default('en')->change(); }); // Context $contexts = DB::table($this->CONTEXT_TABLE) ->get(); foreach ($contexts as $context) { $this->updateSingleValueLocale($context->primary_locale, $this->CONTEXT_TABLE, 'primary_locale', $this->CONTEXT_COLUMN, $context->{$this->CONTEXT_COLUMN}); } $contextSettingsFormLocales = DB::table($this->CONTEXT_SETTINGS_TABLE) ->where('setting_name', '=', 'supportedFormLocales') ->get(); foreach ($contextSettingsFormLocales as $contextSettingsFormLocale) { $this->updateArrayLocaleSetting($contextSettingsFormLocale->setting_value, $this->CONTEXT_SETTINGS_TABLE, 'supportedFormLocales', $this->CONTEXT_COLUMN, $contextSettingsFormLocale->{$this->CONTEXT_COLUMN}); } $contextSettingsFormLocales = DB::table($this->CONTEXT_SETTINGS_TABLE) ->where('setting_name', '=', 'supportedLocales') ->get(); foreach ($contextSettingsFormLocales as $contextSettingsFormLocale) { $this->updateArrayLocaleSetting($contextSettingsFormLocale->setting_value, $this->CONTEXT_SETTINGS_TABLE, 'supportedLocales', $this->CONTEXT_COLUMN, $contextSettingsFormLocale->{$this->CONTEXT_COLUMN}); } $contextSettingsFormLocales = DB::table($this->CONTEXT_SETTINGS_TABLE) ->where('setting_name', '=', 'supportedSubmissionLocales') ->get(); foreach ($contextSettingsFormLocales as $contextSettingsFormLocale) { $this->updateArrayLocaleSetting($contextSettingsFormLocale->setting_value, $this->CONTEXT_SETTINGS_TABLE, 'supportedSubmissionLocales', $this->CONTEXT_COLUMN, $contextSettingsFormLocale->{$this->CONTEXT_COLUMN}); } // plugin_settings // customBlockManager $blockPluginName = 'customblockmanagerplugin'; $blockLocalizedSettingNames = ['blockTitle', 'blockContent']; $contextIds = DB::table($this->CONTEXT_TABLE) ->get() ->pluck($this->CONTEXT_COLUMN); foreach ($contextIds as $contextId) { $blocks = DB::table('plugin_settings') ->where('plugin_name', '=', $blockPluginName) ->where('setting_name', '=', 'blocks') ->where('context_id', '=', $contextId) ->get() ->pluck('setting_value'); if (!$blocks->isEmpty()) { $blocksArray = json_decode($blocks[0], true); foreach ($blocksArray as $block) { foreach ($blockLocalizedSettingNames as $blockLocalizedSettingName) { $blockLocalizedContent = DB::table('plugin_settings') ->where('plugin_name', '=', $block) ->where('setting_name', '=', $blockLocalizedSettingName) ->where('context_id', '=', $contextId) ->first(); if (isset($blockLocalizedContent)) { $this->updateArrayKeysLocaleSetting($blockLocalizedContent->setting_value, 'plugin_settings', 'plugin_setting_id', $blockLocalizedContent->plugin_setting_id); } } } $pluginSettingsDao = DAORegistry::getDAO('PluginSettingsDAO'); /** @var PluginSettingsDAO $pluginSettingsDao */ $cache = $pluginSettingsDao->_getCache($contextId, $blockPluginName); $cache->flush(); } } } public function updateArrayLocaleNoId(string $dbLocales, string $table, string $column) { $siteSupportedLocales = json_decode($dbLocales) ?? []; if ($siteSupportedLocales !== false) { $newLocales = []; foreach ($siteSupportedLocales as $siteSupportedLocale) { $updatedLocale = $this->getUpdatedLocale($siteSupportedLocale); if (!is_null($updatedLocale)) { if (!in_array($updatedLocale, $newLocales)) { $newLocales[] = $updatedLocale; } } else { $newLocales[] = $siteSupportedLocale; } } DB::table($table) ->update([ $column => $newLocales ]); } } public function updateArrayLocale(string $dbLocales, string $table, string $column, string $tableKeyColumn, int $id) { $siteSupportedLocales = json_decode($dbLocales) ?? []; $newLocales = []; foreach ($siteSupportedLocales as $siteSupportedLocale) { $updatedLocale = $this->getUpdatedLocale($siteSupportedLocale); if (!is_null($updatedLocale)) { if (!in_array($updatedLocale, $newLocales)) { $newLocales[] = $updatedLocale; } } else { $newLocales[] = $siteSupportedLocale; } } DB::table($table) ->where($tableKeyColumn, '=', $id) ->update([ $column => $newLocales ]); } public function updateArrayLocaleSetting(string $dbLocales, string $table, string $settingValue, string $tableKeyColumn, int $id) { $siteSupportedLocales = json_decode($dbLocales) ?? []; if ($siteSupportedLocales !== false) { $newLocales = []; foreach ($siteSupportedLocales as $siteSupportedLocale) { $updatedLocale = $this->getUpdatedLocale($siteSupportedLocale); if (!is_null($updatedLocale)) { if (!in_array($updatedLocale, $newLocales)) { $newLocales[] = $updatedLocale; } } else { $newLocales[] = $siteSupportedLocale; } } DB::table($table) ->where($tableKeyColumn, '=', $id) ->where('setting_name', '=', $settingValue) ->update([ 'setting_value' => $newLocales ]); } } public function updateArrayKeysLocaleSetting(string $dbLocales, string $table, string $tableKeyColumn, int $id) { $siteSupportedLocales = json_decode($dbLocales, true) ?? []; if ($siteSupportedLocales !== false) { $newLocales = []; foreach (array_keys($siteSupportedLocales) as $siteSupportedLocaleKey) { $updatedLocale = $this->getUpdatedLocale($siteSupportedLocaleKey); if (!is_null($updatedLocale)) { $newLocales[$updatedLocale] = $siteSupportedLocales[$siteSupportedLocaleKey]; } else { $newLocales[$siteSupportedLocaleKey] = $siteSupportedLocales[$siteSupportedLocaleKey]; } } $jsonString = json_encode($newLocales); DB::table($table) ->where($tableKeyColumn, '=', $id) ->update([ 'setting_value' => $jsonString ]); } } public function updateSingleValueLocale(?string $localevalue, string $table, string $column, string $tableKeyColumn, int $id) { if ($localevalue === null) { return; } $updatedLocale = $this->getUpdatedLocale($localevalue); if (!is_null($updatedLocale)) { DB::table($table) ->where($tableKeyColumn, '=', $id) ->update([ $column => $updatedLocale ]); } } public function updateSingleValueLocaleNoId(string $localevalue, string $table, string $column) { $updatedLocale = $this->getUpdatedLocale($localevalue); if (!is_null($updatedLocale)) { DB::table($table) ->update([ $column => $updatedLocale ]); } } public function updateSingleValueLocaleEmailData(string $localevalue, string $table, string $email_key, Collection $allEmailTemplateData) { $localeRows = DB::table($table) ->where('email_key', '=', $email_key) ->where('locale', '=', $localevalue); $stillExists = $localeRows->exists(); if ($stillExists) { $updatedLocale = $this->getUpdatedLocale($localevalue); // if this is null we should do nothing - we are not handling this locale if (!is_null($updatedLocale)) { // if the updatedLocale is the same as the setting's locale we should do nothing // Check if the database already has an updated locale with the same value - $hasAlreadyExistingUpdatedLocale = DB::table($table) ->where('email_key', '=', $email_key) ->where('locale', '=', $updatedLocale) ->exists(); // if so, it is safe to delete the currently processed value. if ($hasAlreadyExistingUpdatedLocale) { $localeRows->delete(); } else { $localeRows->update(['locale' => $updatedLocale]); } } } } /** * Returns null if no conversion is available or * a key value pair collection that the key is the output locale and the value is the defaultLocale. */ public function getUpdatedLocale(string $localeValue): ?string { $affectedLocales = $this->getAffectedLocales(); if ($affectedLocales->keys()->contains($localeValue)) { $localeTransformation = $affectedLocales[$localeValue]; return $localeTransformation; } return null; } /** * Reverse the downgrades * * @throws DowngradeNotSupportedException */ public function down(): void { throw new DowngradeNotSupportedException(); } /** * Get a list of settings tables, keyed by table name. Values are [entity_id_column_name, settings_table_id_column_name]. */ protected static function getSettingsTables(): Collection { return collect([ 'announcement_settings' => ['announcement_id', 'announcement_setting_id'], 'announcement_type_settings' => ['type_id', 'announcement_type_setting_id'], 'author_settings' => ['author_id', 'author_setting_id'], 'category_settings' => ['category_id', 'category_setting_id'], 'citation_settings' => ['citation_id', 'citation_setting_id'], 'controlled_vocab_entry_settings' => ['controlled_vocab_entry_id', 'controlled_vocab_entry_setting_id'], 'data_object_tombstone_settings' => ['tombstone_id', 'tombstone_setting_id'], 'email_templates_settings' => ['email_id', 'email_template_setting_id'], 'event_log_settings' => ['log_id', 'event_log_setting_id'], 'filter_settings' => ['filter_id', 'filter_setting_id'], 'genre_settings' => ['genre_id', 'genre_setting_id'], 'library_file_settings' => ['file_id', 'library_file_setting_id'], 'navigation_menu_item_assignment_settings' => ['navigation_menu_item_assignment_id', 'navigation_menu_item_assignment_setting_id'], 'navigation_menu_item_settings' => ['navigation_menu_item_id', 'navigation_menu_item_setting_id'], 'notification_settings' => ['notification_id', 'notification_setting_id'], 'notification_subscription_settings' => ['setting_id', 'notification_subscription_setting_id'], 'plugin_settings' => ['context_id', 'plugin_setting_id'], 'publication_settings' => ['publication_id', 'publication_setting_id'], 'review_form_element_settings' => ['review_form_element_id', 'review_form_element_setting_id'], 'review_form_settings' => ['review_form_id', 'review_form_setting_id'], 'submission_file_settings' => ['submission_file_id', 'submission_file_setting_id'], 'submission_settings' => ['submission_id', 'submission_setting_id'], 'user_group_settings' => ['user_group_id', 'user_group_setting_id'], 'user_settings' => ['user_id', 'user_setting_id'], 'site_settings' => [null, 'site_setting_id'], 'funder_settings' => ['funder_id', 'funder_setting_id'], 'funder_award_settings' => ['funder_award_id', 'funder_award_setting_id'], 'static_page_settings' => ['static_page_id', 'static_page_setting_id'], ]); } /** * Returns the effected locales along with the corresponding rename for each */ public static function getAffectedLocales(): Collection { return collect([ 'es_ES' => 'es', 'en_US' => 'en', 'sr_RS@cyrillic' => 'sr@cyrillic', 'sr_RS@latin' => 'sr@latin', 'el_GR' => 'el', 'de_DE' => 'de', 'da_DK' => 'da', 'cs_CZ' => 'cs', 'ca_ES' => 'ca', 'bs_BA' => 'bs', 'bg_BG' => 'bg', 'be_BY@cyrillic' => 'be@cyrillic', 'az_AZ' => 'az', 'ar_IQ' => 'ar', 'fa_IR' => 'fa', 'fi_FI' => 'fi', 'gd_GB' => 'gd', 'gl_ES' => 'gl', 'he_IL' => 'he', 'hi_IN' => 'hi', 'hr_HR' => 'hr', 'hu_HU' => 'hu', 'hy_AM' => 'hy', 'id_ID' => 'id', 'is_IS' => 'is', 'it_IT' => 'it', 'ja_JP' => 'ja', 'ka_GE' => 'ka', 'kk_KZ' => 'kk', 'ko_KR' => 'ko', 'ku_IQ' => 'ku', 'lt_LT' => 'lt', 'lv_LV' => 'lv', 'mk_MK' => 'mk', 'mn_MN' => 'mn', 'ms_MY' => 'ms', 'nb_NO' => 'nb', 'nl_NL' => 'nl', 'pl_PL' => 'pl', 'ro_RO' => 'ro', 'ru_RU' => 'ru', 'si_LK' => 'si', 'sk_SK' => 'sk', 'sl_SI' => 'sl', 'sv_SE' => 'sv', 'tr_TR' => 'tr', 'uk_UA' => 'uk', 'ur_PK' => 'ur', 'uz_UZ@cyrillic' => 'uz@cyrillic', 'uz_UZ@latin' => 'uz@latin', 'vi_VN' => 'vi', 'eu_ES' => 'eu', 'sw_KE' => 'sw', 'zh_TW' => 'zh_Hant' ]); } }