From fd9546c2c1258ee1fb4eb197b1217d151577d709 Mon Sep 17 00:00:00 2001 From: Touhidur Rahman Date: Mon, 11 Nov 2024 23:39:46 +0600 Subject: [PATCH] pkp/pkp-lib#1660 migration to import existing recommendations --- .../ReviewerRecommendationResource.php | 1 + .../context/ReviewerRecommendationForm.php | 6 +- .../ReviewerRecommendationsMigration.php | 39 +---- .../v3_6_0/I1660_ReviewerRecommendations.php | 154 ++++++++++++++++++ .../recommendation/ReviewerRecommendation.php | 62 ++++++- 5 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 classes/migration/upgrade/v3_6_0/I1660_ReviewerRecommendations.php diff --git a/api/v1/reviewers/recommendations/resources/ReviewerRecommendationResource.php b/api/v1/reviewers/recommendations/resources/ReviewerRecommendationResource.php index 0597593d014..ed630eda26f 100644 --- a/api/v1/reviewers/recommendations/resources/ReviewerRecommendationResource.php +++ b/api/v1/reviewers/recommendations/resources/ReviewerRecommendationResource.php @@ -28,6 +28,7 @@ public function toArray(Request $request) return [ 'id' => $this->id, 'contextId' => $this->contextId, + 'value' => $this->value, 'status' => $this->status, 'removable' => $this->removable, 'title' => $this->title, diff --git a/classes/components/forms/context/ReviewerRecommendationForm.php b/classes/components/forms/context/ReviewerRecommendationForm.php index 71ec26d0f87..a5449fc4c70 100644 --- a/classes/components/forms/context/ReviewerRecommendationForm.php +++ b/classes/components/forms/context/ReviewerRecommendationForm.php @@ -47,14 +47,14 @@ public function __construct($action, $locales) 'options' => [ [ 'label' => __('manager.reviewerRecommendations.activateUponSaving.label'), - 'value' => true, + 'value' => 1, ], [ 'label' => __('manager.reviewerRecommendations.activateUponSaving.deactivate'), - 'value' => false, + 'value' => 0, ], ], - 'value' => true, + 'value' => 1, 'size' => 'normal', ])); } diff --git a/classes/migration/install/ReviewerRecommendationsMigration.php b/classes/migration/install/ReviewerRecommendationsMigration.php index 1989b071e73..c99f858d8b7 100644 --- a/classes/migration/install/ReviewerRecommendationsMigration.php +++ b/classes/migration/install/ReviewerRecommendationsMigration.php @@ -17,12 +17,17 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; +use PKP\facades\Locale; +use PKP\submission\reviewer\recommendation\ReviewerRecommendation; +use stdClass; use Throwable; abstract class ReviewerRecommendationsMigration extends \PKP\migration\Migration { abstract public function contextTable(): string; + abstract public function settingTable(): string; + abstract public function contextPrimaryKey(): string; /** @@ -45,6 +50,9 @@ public function up(): void $table->index(['context_id'], 'reviewer_recommendations_context_id'); + $table->unsignedInteger('value'); + $table->unique(['context_id', 'value'], 'reviewer_recommendations_context_unique'); + $table ->boolean('status') ->default(true) @@ -81,7 +89,6 @@ public function up(): void $table->unique(['recommendation_id', 'locale', 'setting_name'], 'reviewer_recommendation_settings_unique'); $table->index(['setting_name', 'locale'], 'reviewer_recommendation_settings_locale_setting_name_index'); }); - } /** @@ -94,34 +101,4 @@ public function down(): void Schema::drop('reviewer_recommendation_settings'); Schema::enableForeignKeyConstraints(); } - - // TODO : need a way to store existing non removable recommendations - protected function seedNonRemovableRecommendations(): void - { - $recommendations = $this->systemDefineNonRemovableRecommendations(); - - if (empty($recommendations)) { - return; - } - - try { - - DB::beginTransaction(); - - // Store data - - DB::commit(); - - } catch (Throwable $exception) { - - DB::rollBack(); - - throw $exception; - } - } - - protected function systemDefineNonRemovableRecommendations(): array - { - return []; - } } diff --git a/classes/migration/upgrade/v3_6_0/I1660_ReviewerRecommendations.php b/classes/migration/upgrade/v3_6_0/I1660_ReviewerRecommendations.php new file mode 100644 index 00000000000..2ab8eeee13d --- /dev/null +++ b/classes/migration/upgrade/v3_6_0/I1660_ReviewerRecommendations.php @@ -0,0 +1,154 @@ +recommendationInstallMigration = new ReviewerRecommendationsMigration( + $installer, + $attributes + ); + + parent::__construct($installer, $attributes); + } + + /** + * Run the migration. + */ + public function up(): void + { + $this->recommendationInstallMigration->up(); + } + + /** + * Reverse the migration + */ + public function down(): void + { + $this->recommendationInstallMigration->down(); + } + + // TODO : Optimize the process if possible + protected function seedNonRemovableRecommendations(): void + { + $nonRemovablerecommendations = $this->systemDefineNonRemovableRecommendations(); + + if (empty($nonRemovablerecommendations)) { + return; + } + + $currentLocale = Locale::getLocale(); + $contextSupportedLocales = DB::table($this->recommendationInstallMigration->contextTable()) + ->select($this->recommendationInstallMigration->contextPrimaryKey()) + ->addSelect([ + "supportedLocales" => DB::table($this->recommendationInstallMigration->settingTable()) + ->select("setting_value") + ->whereColumn( + $this->recommendationInstallMigration->contextPrimaryKey(), + "{$this->recommendationInstallMigration->contextTable()}.{$this->recommendationInstallMigration->contextPrimaryKey()}" + ) + ->where("setting_name", "supportedLocales") + ->limit(1) + ]) + ->get() + ->pluck("supportedLocales", $this->recommendationInstallMigration->contextPrimaryKey()) + ->filter() + ->map(fn($locales) => json_decode($locales)); + + try { + + $recommendations = []; + + foreach ($nonRemovablerecommendations as $recommendationValue => $translatableKey) { + $recommendations[$recommendationValue] = [ + 'contextId' => null, + 'value' => $recommendationValue, + 'removable' => 0, + 'status' => 1, + 'title' => [], + ]; + } + + $allContextSupportLocales = $contextSupportedLocales + ->values() + ->flatten() + ->unique() + ->toArray(); + + ReviewerRecommendation::unguard(); + + DB::beginTransaction(); + + foreach ($allContextSupportLocales as $locale) { + + Locale::setLocale($locale); + + foreach ($nonRemovablerecommendations as $recommendationValue => $translatableKey) { + $recommendations[$recommendationValue]['title'][$locale] = __($translatableKey); + } + } + + Locale::setLocale($currentLocale); + + $contextSupportedLocales->each( + fn (array $supportedLocales, int $contextId) => collect($recommendations)->each( + fn (array $recommendation) => + ReviewerRecommendation::create( + array_merge($recommendation, [ + 'contextId' => $contextId, + 'title' => array_intersect_key( + $recommendation['title'], + array_flip($supportedLocales) + ) + ]) + ) + ) + ); + + DB::commit(); + + ReviewerRecommendation::reguard(); + + } catch (Throwable $exception) { + + DB::rollBack(); + Locale::setLocale($currentLocale); + ReviewerRecommendation::reguard(); + + ray($exception); + throw $exception; + } + } +} diff --git a/classes/submission/reviewer/recommendation/ReviewerRecommendation.php b/classes/submission/reviewer/recommendation/ReviewerRecommendation.php index 6d8be052e39..a56603c3751 100644 --- a/classes/submission/reviewer/recommendation/ReviewerRecommendation.php +++ b/classes/submission/reviewer/recommendation/ReviewerRecommendation.php @@ -4,10 +4,12 @@ use APP\facades\Repo; use APP\core\Application; +use Exception; use PKP\core\traits\ModelWithSettings; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; +use PKP\submission\reviewer\recommendation\cast\ReviewerRecommendationValueCast; class ReviewerRecommendation extends Model { @@ -35,12 +37,23 @@ class ReviewerRecommendation extends Model protected function casts(): array { return [ + 'value' => 'integer', 'context_id' => 'integer', - 'status' => 'boolean', + 'status' => 'integer', // We cast the boolean to corresponding int e.g. true/false to 1/0 'removable' => 'boolean', ]; } + /** + * The "booted" method of the model. + */ + protected static function booted(): void + { + static::creating(function (Model $recommendation) { + $recommendation->value = $recommendation->value; + }); + } + /** * @copydoc \PKP\core\traits\ModelWithSettings::getSettingsTable */ @@ -76,6 +89,43 @@ public function getMultilingualProps(): array 'title', ]; } + + protected function value(): Attribute + { + return Attribute::make( + set: function (?int $value) { + if ($this->getRawOriginal('value')) { + return $this->getRawOriginal('value'); + } + + if ($value) { + $existingRecommendation = static::query() + ->withContextId($this->contextId) + ->where('value', $value) + ->first(); + + if ($existingRecommendation) { + throw new Exception( + "Given recommendation value : {$value} already exist for given context" + ); + } + + return $value; + } + + $lastRecommendationValue = static::query() + ->withContextId($this->contextId) + ->when( + $this->id, + fn ($query) => $query->where($this->getKeyName(), '!=', $this->id) + ) + ->orderBy($this->getKeyName(), 'desc') + ->first()?->value ?? 0; + + return $lastRecommendationValue + 1; + } + ); + } protected function removable(): Attribute { @@ -87,13 +137,17 @@ protected function removable(): Attribute $reviewAssignmentCount = Repo::reviewAssignment() ->getCollector() - ->filterByRecommenddations([$this->id]) + ->filterByRecommenddations([$this->value]) ->getCount(); return $reviewAssignmentCount === 0; }, - set: function () { - return $this->getRawOriginal('removable'); + // TODO : MUST FIX ME !!! This cause issue at data seeding in migration process + set: function (bool $value) { + if (!is_null($this->getRawOriginal('removable'))) { + return $this->getRawOriginal('removable'); + } + return $value; } )->shouldCache(); }