diff --git a/classes/migration/install/OJSMigration.php b/classes/migration/install/OJSMigration.php index c44df195950..7e9be1455d4 100644 --- a/classes/migration/install/OJSMigration.php +++ b/classes/migration/install/OJSMigration.php @@ -38,7 +38,7 @@ public function up(): void $table->foreign('review_form_id', 'sections_review_form_id')->references('review_form_id')->on('review_forms')->onDelete('set null'); $table->index(['review_form_id'], 'sections_review_form_id'); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->smallInteger('editor_restricted')->default(0); $table->smallInteger('meta_indexed')->default(0); $table->smallInteger('meta_reviewed')->default(1); @@ -114,12 +114,12 @@ public function up(): void $table->unique(['issue_id', 'locale', 'setting_name'], 'issue_settings_unique'); }); // Add partial index (DBMS-specific) - switch (DB::getDriverName()) { - case 'mysql': DB::unprepared('CREATE INDEX issue_settings_name_value ON issue_settings (setting_name(50), setting_value(150))'); - break; - case 'pgsql': DB::unprepared("CREATE INDEX issue_settings_name_value ON issue_settings (setting_name, setting_value) WHERE setting_name IN ('medra::registeredDoi', 'datacite::registeredDoi')"); - break; - } + match (DB::getDriverName()) { + 'mysql', 'mariadb' => + DB::unprepared('CREATE INDEX issue_settings_name_value ON issue_settings (setting_name(50), setting_value(150))'), + 'pgsql' => + DB::unprepared("CREATE INDEX issue_settings_name_value ON issue_settings (setting_name, setting_value) WHERE setting_name IN ('medra::registeredDoi', 'datacite::registeredDoi')") + }; Schema::create('issue_files', function (Blueprint $table) { $table->comment('Relationships between issues and issue files, such as cover images.'); @@ -154,7 +154,7 @@ public function up(): void $table->index(['file_id'], 'issue_galleys_file_id'); $table->string('label', 255)->nullable(); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->string('url_path', 64)->nullable(); $table->index(['url_path'], 'issue_galleys_url_path'); @@ -189,7 +189,7 @@ public function up(): void $table->foreign('journal_id', 'custom_issue_orders_journal_id')->references('journal_id')->on('journals')->onDelete('cascade'); $table->index(['journal_id'], 'custom_issue_orders_journal_id'); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->unique(['issue_id'], 'custom_issue_orders_unique'); }); @@ -206,7 +206,7 @@ public function up(): void $table->foreign('section_id', 'custom_section_orders_section_id')->references('section_id')->on('sections')->onDelete('cascade'); $table->index(['section_id'], 'custom_section_orders_section_id'); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->unique(['issue_id', 'section_id'], 'custom_section_orders_unique'); }); @@ -228,7 +228,7 @@ public function up(): void $table->foreign('section_id', 'publications_section_id')->references('section_id')->on('sections')->onDelete('set null'); $table->index(['section_id'], 'publications_section_id'); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->bigInteger('submission_id'); $table->foreign('submission_id', 'publications_submission_id')->references('submission_id')->on('submissions')->onDelete('cascade'); @@ -243,7 +243,7 @@ public function up(): void $table->index(['doi_id'], 'publications_doi_id'); $table->bigInteger('issue_id')->nullable(); - $table->foreign('issue_id')->references('issue_id')->on('issues')->onDelete('set null'); + $table->foreign('issue_id')->references('issue_id')->on('issues')->nullOnDelete(); $table->index(['issue_id'], 'publications_issue_id_index'); $table->index(['url_path'], 'publications_url_path'); @@ -278,7 +278,7 @@ public function up(): void $table->foreign('submission_file_id')->references('submission_file_id')->on('submission_files'); $table->index(['submission_file_id'], 'publication_galleys_submission_file_id'); - $table->float('seq', 8, 2)->default(0); + $table->float('seq')->default(0); $table->string('remote_url', 2047)->nullable(); $table->smallInteger('is_approved')->default(0); $table->string('url_path', 64)->nullable(); @@ -306,12 +306,12 @@ public function up(): void $table->unique(['galley_id', 'locale', 'setting_name'], 'publication_galley_settings_unique'); }); // Add partial index (DBMS-specific) - switch (DB::getDriverName()) { - case 'mysql': DB::unprepared('CREATE INDEX publication_galley_settings_name_value ON publication_galley_settings (setting_name(50), setting_value(150))'); - break; - case 'pgsql': DB::unprepared('CREATE INDEX publication_galley_settings_name_value ON publication_galley_settings (setting_name, setting_value)'); - break; - } + match (DB::getDriverName()) { + 'mysql', 'mariadb' => + DB::unprepared('CREATE INDEX publication_galley_settings_name_value ON publication_galley_settings (setting_name(50), setting_value(150))'), + 'pgsql' => + DB::unprepared('CREATE INDEX publication_galley_settings_name_value ON publication_galley_settings (setting_name, setting_value)') + }; // Subscription types. Schema::create('subscription_types', function (Blueprint $table) { @@ -322,14 +322,14 @@ public function up(): void $table->foreign('journal_id', 'subscription_types_journal_id')->references('journal_id')->on('journals')->onDelete('cascade'); $table->index(['journal_id'], 'subscription_types_journal_id'); - $table->float('cost', 8, 2); + $table->decimal('cost', 8, 2)->unsigned(); $table->string('currency_code_alpha', 3); $table->smallInteger('duration')->nullable(); $table->smallInteger('format'); $table->smallInteger('institutional')->default(0); $table->smallInteger('membership')->default(0); $table->smallInteger('disable_public_display'); - $table->float('seq', 8, 2); + $table->float('seq'); }); // Locale-specific subscription type data @@ -419,7 +419,7 @@ public function up(): void $table->index(['user_id'], 'completed_payments_user_id'); $table->bigInteger('assoc_id')->nullable(); - $table->float('amount', 8, 2); + $table->decimal('amount', 8, 2)->unsigned(); $table->string('currency_code_alpha', 3)->nullable(); $table->string('payment_method_plugin_name', 80)->nullable(); }); diff --git a/classes/migration/upgrade/v3_4_0/I7901_Duplicate_OAI_IDs.php b/classes/migration/upgrade/v3_4_0/I7901_Duplicate_OAI_IDs.php index 02c1c5c3e3a..ebb5537ba42 100644 --- a/classes/migration/upgrade/v3_4_0/I7901_Duplicate_OAI_IDs.php +++ b/classes/migration/upgrade/v3_4_0/I7901_Duplicate_OAI_IDs.php @@ -21,30 +21,30 @@ class I7901_Duplicate_OAI_IDs extends \PKP\migration\Migration */ public function up(): void { - switch (DB::getDriverName()) { - case 'mysql': + match (DB::getDriverName()) { + 'mysql', 'mariadb' => DB::unprepared( - 'DELETE dot + "DELETE dot FROM data_object_tombstones dot JOIN submissions s ON (dot.data_object_id = s.submission_id) JOIN journals j ON (j.journal_id = s.context_id) JOIN publications p ON (s.current_publication_id = p.publication_id) - JOIN issues i ON (i.issue_id = p.issue_id) - WHERE i.published = 1 AND j.enabled = 1 AND p.status = 3' - ); - break; - case 'pgsql': + JOIN publication_settings psissue ON (psissue.publication_id = p.publication_id AND psissue.setting_name='issueId' AND psissue.locale='') + JOIN issues i ON (CAST(i.issue_id AS CHAR(20)) = psissue.setting_value) + WHERE i.published = 1 AND j.enabled = 1 AND p.status = 3" + ), + 'pgsql' => DB::unprepared( - 'DELETE FROM data_object_tombstones dot - USING submissions s, journals j, publications p, issues i + "DELETE FROM data_object_tombstones dot + USING submissions s, journals j, publications p, publication_settings psissue, issues i WHERE dot.data_object_id = s.submission_id AND j.journal_id = s.context_id AND s.current_publication_id = p.publication_id - AND i.issue_id = p.issue_id - AND i.published = 1 AND j.enabled = 1 AND p.status = 3' - ); - break; - } + AND psissue.publication_id = p.publication_id + AND psissue.setting_name='issueId' AND psissue.locale='' AND (CAST(i.issue_id AS CHAR(20)) = psissue.setting_value) + AND i.published = 1 AND j.enabled = 1 AND p.status = 3" + ) + }; } /** diff --git a/classes/migration/upgrade/v3_4_0/PreflightCheckMigration.php b/classes/migration/upgrade/v3_4_0/PreflightCheckMigration.php index 9a324db5161..eeee680aab7 100644 --- a/classes/migration/upgrade/v3_4_0/PreflightCheckMigration.php +++ b/classes/migration/upgrade/v3_4_0/PreflightCheckMigration.php @@ -90,23 +90,9 @@ protected function buildOrphanedEntityProcessor(): void } $affectedRows += $this->deleteOptionalReference('publications', 'section_id', 'sections', 'section_id'); // Remaining cleanups are inherited - $rows = DB::table('publications AS p') - ->leftJoin('issues AS i', 'p.issue_id', '=', 'i.issue_id') - ->whereNull('i.issue_id') - ->whereNotNull('p.issue_id') // Ensure we're only looking at non-null issue_ids - ->select('p.submission_id', 'p.publication_id', 'p.issue_id') - ->get(); - - foreach ($rows as $row) { - $this->_installer->log("The publication ID ({$row->publication_id}) for the submission ID {$row->submission_id} is assigned to an invalid issue ID \"{$row->issue_id}\", its issue_id will be set to NULL."); - $affectedRows += DB::table('publications') - ->where('publication_id', '=', $row->publication_id) - ->update(['issue_id' => null]); // Reset invalid issue_id to null - } return $affectedRows; }); - $this->addTableProcessor('publication_galleys', function (): int { $affectedRows = 0; // Depends directly on ~3 entities: doi_id->dois.doi_id(not found in previous version) publication_id->publications.publication_id submission_file_id->submission_files.submission_file_id @@ -243,6 +229,25 @@ protected function buildOrphanedEntityProcessor(): void return $affectedRows; }); + // Support for the issueId setting + $this->addTableProcessor('publication_settings', function (): int { + $affectedRows = 0; + $rows = DB::table('publications AS p') + ->join('publication_settings AS ps', 'ps.publication_id', '=', 'p.publication_id') + ->leftJoin('issues AS i', 'ps.setting_value', '=', DB::raw('CAST(i.issue_id AS CHAR(20))')) + ->where('ps.setting_name', 'issueId') + ->whereNull('i.issue_id') + ->get(['p.submission_id', 'p.publication_id', 'ps.setting_value']); + foreach ($rows as $row) { + $this->_installer->log("The publication ID ({$row->publication_id}) for the submission ID {$row->submission_id} is assigned to an invalid issue ID \"{$row->setting_value}\", its value will be updated to NULL"); + $affectedRows += DB::table('publication_settings') + ->where('publication_id', '=', $row->publication_id) + ->where('setting_name', 'issueId') + ->where('setting_value', $row->setting_value) + ->delete(); + } + return $affectedRows; + }); } protected function getEntityRelationships(): array @@ -296,7 +301,7 @@ protected function getEntityRelationships(): array protected function dropForeignKeys(): void { parent::dropForeignKeys(); - if (DB::getDoctrineSchemaManager()->introspectTable('publication_galleys')->hasForeignKey('publication_galleys_submission_file_id_foreign')) { + if ($this->hasForeignKey('publication_galleys', 'publication_galleys_submission_file_id_foreign')) { Schema::table('publication_galleys', fn (Blueprint $table) => $table->dropForeign('publication_galleys_submission_file_id_foreign')); } } diff --git a/classes/migration/upgrade/v3_5_0/I10157_CreateAndMigrateIssueIdField.php b/classes/migration/upgrade/v3_5_0/I10157_CreateAndMigrateIssueIdField.php new file mode 100644 index 00000000000..138712f4f19 --- /dev/null +++ b/classes/migration/upgrade/v3_5_0/I10157_CreateAndMigrateIssueIdField.php @@ -0,0 +1,39 @@ +bigInteger('issue_id')->nullable()->after('submission_id'); + }); + + // migrating data from publication_settings to the new issue_id column + DB::statement('UPDATE publications p JOIN publication_settings ps ON p.publication_id = ps.publication_id AND ps.setting_name = "issueId" SET p.issue_id = ps.setting_value'); + + // clear the old data of issueId in publication_settings + DB::table('publication_settings')->where('setting_name', 'issueId')->delete(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // remove the column in case rolling back + Schema::table('publications', function (Blueprint $table) { + $table->dropColumn('issue_id'); + }); + } +} diff --git a/classes/oai/ojs/OAIDAO.php b/classes/oai/ojs/OAIDAO.php index eca0b6e7e0c..3e3f297e865 100644 --- a/classes/oai/ojs/OAIDAO.php +++ b/classes/oai/ojs/OAIDAO.php @@ -272,7 +272,6 @@ public function _getRecordsRecordSetQuery($setIds, $from, $until, $set, $submiss ]) ->join('publications AS p', 'a.current_publication_id', '=', 'p.publication_id') ->join('issues AS i', 'i.issue_id', '=', 'p.issue_id') - ->join('issues AS i', DB::raw('CAST(i.issue_id AS CHAR(20))'), '=', 'psissue.setting_value') ->join('sections AS s', 's.section_id', '=', 'p.section_id') ->join('journals AS j', 'j.journal_id', '=', 'a.context_id') ->where('i.published', '=', 1) diff --git a/classes/search/ArticleSearchDAO.php b/classes/search/ArticleSearchDAO.php index 0a862aa6637..d841833a197 100644 --- a/classes/search/ArticleSearchDAO.php +++ b/classes/search/ArticleSearchDAO.php @@ -92,8 +92,7 @@ public function getPhraseResults($journal, $phrase, $publishedFrom = null, $publ FROM submissions s JOIN publications p ON (p.publication_id = s.current_publication_id) - JOIN issues i ON (i.issue_id = p.issue_id AND i.journal_id = s.context_id) - JOIN issues i ON (CAST(i.issue_id AS CHAR(20)) = ps.setting_value AND i.journal_id = s.context_id) + JOIN issues i ON (i.issue_id = p.issue_id) JOIN submission_search_objects o ON (s.submission_id = o.submission_id) JOIN journals j ON j.journal_id = s.context_id LEFT JOIN journal_settings js ON j.journal_id = js.journal_id AND js.setting_name = \'publishingMode\' diff --git a/classes/services/queryBuilders/StatsGeoQueryBuilder.php b/classes/services/queryBuilders/StatsGeoQueryBuilder.php index abd3dfa34bd..bda976d7559 100644 --- a/classes/services/queryBuilders/StatsGeoQueryBuilder.php +++ b/classes/services/queryBuilders/StatsGeoQueryBuilder.php @@ -45,13 +45,12 @@ public function filterByIssues(array $issueIds): self protected function _getAppSpecificQuery(Builder &$q): void { if (!empty($this->issueIds)) { - $issueSubmissionIds = DB::table('publications as p') - ->select('p.submission_id') - ->distinct() - ->where('p.status', Submission::STATUS_PUBLISHED) - ->whereIn('p.issue_id', $this->issueIds); - $q->joinSub($issueSubmissionIds, 'is', function ($join) { - $join->on('metrics_submission_geo_monthly.' . PKPStatisticsHelper::STATISTICS_DIMENSION_SUBMISSION_ID, '=', 'is.submission_id'); + $q->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('publications as p') + ->whereRaw('p.submission_id = metrics_submission_geo_monthly.' . PKPStatisticsHelper::STATISTICS_DIMENSION_SUBMISSION_ID) + ->where('p.status', Submission::STATUS_PUBLISHED) + ->whereIn('p.issue_id', $this->issueIds); }); } } diff --git a/classes/submission/Collector.php b/classes/submission/Collector.php index a9fcf07f7d1..9342edd83e6 100644 --- a/classes/submission/Collector.php +++ b/classes/submission/Collector.php @@ -54,20 +54,12 @@ public function getQueryBuilder(): Builder // By issue IDs if (is_array($this->issueIds)) { - $q->whereIn('s.submission_id', function ($query) { - $query->select('issue_p.submission_id') - ->from('publications AS issue_p') - ->whereIn('issue_p.issue_id', $this->issueIds); - }); + $q->whereIn('po.issue_id', $this->issueIds); } // By section IDs if (is_array($this->sectionIds)) { - $q->whereIn('s.submission_id', function ($query) { - $query->select('section_p.submission_id') - ->from('publications AS section_p') - ->whereIn('section_p.section_id', $this->sectionIds); - }); + $q->whereIn('po.section_id', $this->sectionIds); } return $q; diff --git a/dbscripts/xml/upgrade.xml b/dbscripts/xml/upgrade.xml index 2f925e9d549..94c45e6a628 100644 --- a/dbscripts/xml/upgrade.xml +++ b/dbscripts/xml/upgrade.xml @@ -68,6 +68,7 @@ + @@ -128,6 +129,7 @@ + @@ -146,6 +148,7 @@ +