From e920699b00ab4859c96bb507c53c263e0614fa79 Mon Sep 17 00:00:00 2001 From: Bozana Bokan Date: Wed, 18 Dec 2024 11:27:50 +0100 Subject: [PATCH] pkp/pkp-lib#10729 fix I9707_WeblateUILocales, consider locales in arrays and setting values --- .../I9425_SeparateUIAndSubmissionLocales.php | 63 ++---- .../upgrade/v3_5_0/I9707_WeblateUILocales.php | 203 ++++++++++++++++-- 2 files changed, 202 insertions(+), 64 deletions(-) diff --git a/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php b/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php index 1d631e925d8..4a96d48bb7f 100644 --- a/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php +++ b/classes/migration/upgrade/v3_5_0/I9425_SeparateUIAndSubmissionLocales.php @@ -18,7 +18,6 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; -use APP\core\Application; use PKP\install\DowngradeNotSupportedException; use PKP\migration\Migration; @@ -50,9 +49,9 @@ public function up(): void $update = function (object $localeId, string $settingName, string $settingValue): void { DB::table($this->getContextSettingsTable()) - ->where($this->getContextIdColumn(), '=', $localeId->{$this->getContextIdColumn()}) - ->where('setting_name', '=', $settingName) - ->update(['setting_value' => $settingValue]); + ->where($this->getContextIdColumn(), '=', $localeId->{$this->getContextIdColumn()}) + ->where('setting_name', '=', $settingName) + ->update(['setting_value' => $settingValue]); }; $pluck = fn (object $localeId, string $settingName): array => json_decode( @@ -94,65 +93,27 @@ public function up(): void : 'TABLE_SCHEMA'; $updateLength = fn (string $l) => collect( - DB::select(" - SELECT DISTINCT TABLE_NAME - FROM INFORMATION_SCHEMA.COLUMNS - WHERE COLUMN_NAME = ? AND $schemaLocName = ?", + DB::select( + " + SELECT DISTINCT TABLE_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE COLUMN_NAME = ? AND {$schemaLocName} = ?", [$l, DB::connection()->getDatabaseName()] ) - )->each(fn (\stdClass $sc) => Schema::table( + )->each( + fn (\stdClass $sc) => Schema::table( $sc->TABLE_NAME ?? $sc->table_name, fn (Blueprint $table) => collect(Schema::getColumns($sc->TABLE_NAME ?? $sc->table_name)) ->where('name', $l) ->first(default:[])['nullable'] ?? false - ? $table->string($l, 28)->nullable()->change() - : $table->string($l, 28)->change() + ? $table->string($l, 28)->nullable()->change() + : $table->string($l, 28)->change() ) ); $updateLength('primary_locale'); $updateLength('locale'); - /** - * Convert locales - */ - - $localesTable = [ - "be@cyrillic" => "be", - "bs" => "bs_Latn", - "fr_FR" => "fr", - "nb" => "nb_NO", - "sr@cyrillic" => "sr_Cyrl", - "sr@latin" => "sr_Latn", - "uz@cyrillic" => "uz", - "uz@latin" => "uz_Latn", - "zh_CN" => "zh_Hans", - ]; - - $tableNames = array_merge([ - 'author_settings', - 'controlled_vocab_entry_settings', - 'publication_settings', - 'submission_file_settings', - 'submission_settings', - 'submissions', - ], Application::get()->getName() === 'omp' - ? ['publication_format_settings', 'submission_chapter_settings',] - : ['publication_galley_settings', 'publication_galleys',] - ); - - collect($tableNames) - ->each(fn (string $tn) => collect(DB::table($tn)->select('locale')->distinct()->get()) - ->each(function (\stdClass $sc) use ($tn, $localesTable) { - if (isset($localesTable[$sc->locale])) { - DB::table($tn) - ->where('locale', '=', $sc->locale) - ->update([ - 'locale' => $localesTable[$sc->locale] - ]); - } - }) - ); } /** diff --git a/classes/migration/upgrade/v3_5_0/I9707_WeblateUILocales.php b/classes/migration/upgrade/v3_5_0/I9707_WeblateUILocales.php index e1759f51dc7..f7df4f9c22c 100644 --- a/classes/migration/upgrade/v3_5_0/I9707_WeblateUILocales.php +++ b/classes/migration/upgrade/v3_5_0/I9707_WeblateUILocales.php @@ -15,18 +15,206 @@ namespace PKP\migration\upgrade\v3_5_0; use Illuminate\Database\PostgresConnection; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; use PKP\install\DowngradeNotSupportedException; use PKP\migration\Migration; -class I9707_WeblateUILocales extends Migration +abstract class I9707_WeblateUILocales extends Migration { + protected string $CONTEXT_TABLE = ''; + protected string $CONTEXT_SETTINGS_TABLE = ''; + protected string $CONTEXT_COLUMN = ''; + /** * Run the migrations. */ public function up(): void { - $localesTable = [ + $affectedLocales = $this->getAffectedLocales(); + + // update all locale and primary_locale columns + $schemaLocName = (DB::connection() instanceof PostgresConnection) ? 'TABLE_CATALOG' : 'TABLE_SCHEMA'; + $renameLocale = fn (string $l) => collect(DB::select("SELECT DISTINCT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ? AND {$schemaLocName} = ?", [$l, DB::connection()->getDatabaseName()])) + ->each(function (\stdClass $sc) use ($l, $affectedLocales) { + foreach ($affectedLocales as $uiLocale => $weblateLocale) { + DB::table($sc->TABLE_NAME ?? $sc->table_name)->where($l, '=', $uiLocale)->update([$l => $weblateLocale]); + } + }); + $renameLocale('primary_locale'); + $renameLocale('locale'); + + // site supported and installed locales + $site = DB::table('site') + ->select(['supported_locales', 'installed_locales']) + ->first(); + $this->updateArrayLocale($site->supported_locales, 'site', 'supported_locales'); + $this->updateArrayLocale($site->installed_locales, 'site', 'installed_locales'); + + // users locales + $migration = $this; + DB::table('users')->chunkById(1000, function ($users) use ($migration) { + foreach ($users as $user) { + $migration->updateArrayLocale($user->locales, 'users', 'locales', null, 'user_id', $user->user_id); + } + }, 'user_id'); + + // context supported locales + $supportedDefaultSubmissionLocale = DB::table($this->CONTEXT_SETTINGS_TABLE) + ->where('setting_name', '=', 'supportedDefaultSubmissionLocale') + ->get() + ->pluck('setting_value') + ->first(); + if (in_array($supportedDefaultSubmissionLocale, array_keys($affectedLocales))) { + DB::table($this->CONTEXT_SETTINGS_TABLE) + ->where('setting_name', '=', 'supportedDefaultSubmissionLocale') + ->update(['setting_value' => $affectedLocales[$supportedDefaultSubmissionLocale]]); + } + $contextLocaleSettingNames = [ + 'supportedFormLocales', + 'supportedLocales', + 'supportedSubmissionLocales', + 'supportedAddedSubmissionLocales', + 'supportedSubmissionMetadataLocales', + ]; + foreach ($contextLocaleSettingNames as $contextLocaleSettingName) { + $contextSettingLocales = DB::table($this->CONTEXT_SETTINGS_TABLE) + ->where('setting_name', '=', $contextLocaleSettingName) + ->get(); + foreach ($contextSettingLocales as $contextSettingLocale) { + $this->updateArrayLocale($contextSettingLocale->setting_value, $this->CONTEXT_SETTINGS_TABLE, 'setting_value', $contextLocaleSettingName, $this->CONTEXT_COLUMN, $contextSettingLocale->{$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()) { + $blockNames = $blocks->first(); + + $blocksArray = json_decode($blockNames, true); + if (is_null($blocksArray)) { + $blocksArray = unserialize($blockNames); + } + + 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); + } + } + } + } + } + } + + /** + * Update array of locales + */ + public function updateArrayLocale(string $dbLocales, string $table, string $column, ?string $settingName = null, ?string $tableKeyColumn = null, ?int $id = null) + { + $locales = json_decode($dbLocales) ?: []; + $affectedLocales = $this->getAffectedLocales(); + $localesToMigrate = array_intersect($locales, array_keys($affectedLocales)); + if (empty($localesToMigrate)) { + return; + } + + $newLocales = []; + foreach ($locales as $locale) { + $updatedLocale = $this->getUpdatedLocale($locale); + if (!is_null($updatedLocale)) { + if (!in_array($updatedLocale, $newLocales)) { + $newLocales[] = $updatedLocale; + } + } else { + $newLocales[] = $locale; + } + } + + DB::table($table) + ->when( + isset($tableKeyColumn) && isset($id), + fn (Builder $query) => $query->where($tableKeyColumn, '=', $id) + ) + ->when( + isset($settingName), + fn (Builder $query) => $query->where('setting_name', '=', $settingName) + ) + ->update([ + $column => $newLocales + ]); + } + + /** + * Update locales that are array keys + */ + public function updateArrayKeysLocaleSetting(string $contentArray, string $table, string $tableKeyColumn, int $id) + { + $contentElements = json_decode($contentArray, true) ?: []; + $affectedLocales = $this->getAffectedLocales(); + $localesToMigrate = array_intersect_key($contentElements, $affectedLocales); + if (empty($localesToMigrate)) { + return; + } + + $newLocales = []; + foreach (array_keys($contentElements) as $locale) { + $updatedLocale = $this->getUpdatedLocale($locale); + if (!is_null($updatedLocale)) { + $newLocales[$updatedLocale] = $contentElements[$locale]; + } else { + $newLocales[$locale] = $contentElements[$locale]; + } + } + $jsonString = json_encode($newLocales); + DB::table($table) + ->where($tableKeyColumn, '=', $id) + ->update([ + 'setting_value' => $jsonString + ]); + } + + /** + * Returns null if no conversion is needed or + * the new, converted value. + */ + public function getUpdatedLocale(string $localeValue): ?string + { + $affectedLocales = $this->getAffectedLocales(); + if (!in_array($localeValue, array_keys($affectedLocales))) { + return null; + } + return $affectedLocales[$localeValue]; + } + + /** + * Returns the effected locales along with the corresponding rename for each + */ + public static function getAffectedLocales(): array + { + return [ 'be@cyrillic' => 'be', 'bs' => 'bs_Latn', 'fr_FR' => 'fr', @@ -39,17 +227,6 @@ public function up(): void 'uz@latin' => 'uz_Latn', 'zh_CN' => 'zh_Hans', ]; - - $schemaLocName = (DB::connection() instanceof PostgresConnection) ? 'TABLE_CATALOG' : 'TABLE_SCHEMA'; - $renameLocale = fn (string $l) => collect(DB::select("SELECT DISTINCT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ? AND {$schemaLocName} = ?", [$l, DB::connection()->getDatabaseName()])) - ->each(function (\stdClass $sc) use ($l, $localesTable) { - foreach ($localesTable as $uiLocale => $weblateLocale) { - DB::table($sc->TABLE_NAME ?? $sc->table_name)->where($l, '=', $uiLocale)->update([$l => $weblateLocale]); - } - }); - - $renameLocale('primary_locale'); - $renameLocale('locale'); } /**