diff --git a/classes/submission/Collector.php b/classes/submission/Collector.php index ca84813b7b6..2d4460c426c 100644 --- a/classes/submission/Collector.php +++ b/classes/submission/Collector.php @@ -1,4 +1,5 @@ */ public function getMany(): LazyCollection @@ -318,14 +320,18 @@ public function getQueryBuilder(): Builder case self::ORDERBY_TITLE: $locale = Locale::getLocale(); $q->leftJoin('publications as publication_tlp', 's.current_publication_id', '=', 'publication_tlp.publication_id') - ->leftJoin('publication_settings as publication_tlps', fn (JoinClause $join) => + ->leftJoin( + 'publication_settings as publication_tlps', + fn (JoinClause $join) => $join->on('publication_tlp.publication_id', '=', 'publication_tlps.publication_id') ->where('publication_tlps.setting_name', '=', 'title') ->where('publication_tlps.setting_value', '!=', '') ->where('publication_tlps.locale', '=', $locale) ); $q->leftJoin('publications as publication_tlpl', 's.current_publication_id', '=', 'publication_tlpl.publication_id') - ->leftJoin('publication_settings as publication_tlpsl', fn (JoinClause $join) => + ->leftJoin( + 'publication_settings as publication_tlpsl', + fn (JoinClause $join) => $join->on('publication_tlp.publication_id', '=', 'publication_tlpsl.publication_id') ->on('publication_tlpsl.locale', '=', 's.locale') ->where('publication_tlpsl.setting_name', '=', 'title') @@ -343,10 +349,12 @@ public function getQueryBuilder(): Builder $orderByMatchCount = DB::table('submission_search_objects', 'sso') ->join('submission_search_object_keywords AS ssok', 'ssok.object_id', '=', 'sso.object_id') ->join('submission_search_keyword_list AS sskl', 'sskl.keyword_id', '=', 'ssok.keyword_id') - ->where(fn (Builder $q) => - $keywords->map(fn (string $keyword) => $q - ->orWhere('sskl.keyword_text', '=', DB::raw('LOWER(?)')) - ->addBinding($keyword) + ->where( + fn (Builder $q) => + $keywords->map( + fn (string $keyword) => $q + ->orWhere('sskl.keyword_text', '=', DB::raw('LOWER(?)')) + ->addBinding($keyword) ) ) ->whereColumn('s.submission_id', '=', 'sso.submission_id') @@ -379,41 +387,57 @@ public function getQueryBuilder(): Builder } if ($this->isOverdue) { - $q->leftJoin('review_assignments as raod', 'raod.submission_id', '=', 's.submission_id') - ->leftJoin('review_rounds as rr', fn (Builder $table) => - $table->on('rr.submission_id', '=', 's.submission_id') - ->on('raod.review_round_id', '=', 'rr.review_round_id') - ); - // Only get overdue assignments on active review rounds - $q->whereNotIn('rr.status', [ - ReviewRound::REVIEW_ROUND_STATUS_RESUBMIT_FOR_REVIEW, - ReviewRound::REVIEW_ROUND_STATUS_SENT_TO_EXTERNAL, - ReviewRound::REVIEW_ROUND_STATUS_ACCEPTED, - ReviewRound::REVIEW_ROUND_STATUS_DECLINED, - ]); - $q->where(fn (Builder $q) => - $q->where('raod.declined', '<>', 1) - ->where('raod.cancelled', '<>', 1) - ->where(fn (Builder $q) => - $q->where('raod.date_due', '<', Core::getCurrentDate(strtotime('tomorrow'))) - ->whereNull('raod.date_completed') + $q->whereIn( + 's.submission_id', + fn (Builder $q) => + $q->select('s.submission_id') + ->from('submissions AS s') + ->leftJoin('review_assignments as raod', 'raod.submission_id', '=', 's.submission_id') + ->leftJoin( + 'review_rounds as rr', + fn (Builder $table) => + $table->on('rr.submission_id', '=', 's.submission_id') + ->on('raod.review_round_id', '=', 'rr.review_round_id') ) - ->orWhere(fn (Builder $q) => - $q->where('raod.date_response_due', '<', Core::getCurrentDate(strtotime('tomorrow'))) - ->whereNull('raod.date_confirmed') + ->whereNotIn('rr.status', [ + ReviewRound::REVIEW_ROUND_STATUS_RESUBMIT_FOR_REVIEW, + ReviewRound::REVIEW_ROUND_STATUS_SENT_TO_EXTERNAL, + ReviewRound::REVIEW_ROUND_STATUS_ACCEPTED, + ReviewRound::REVIEW_ROUND_STATUS_DECLINED, + ]) + ->where( + fn (Builder $q) => + $q->where('raod.declined', '<>', 1) + ->where('raod.cancelled', '<>', 1) + ->where( + fn (Builder $q) => + $q->where('raod.date_due', '<', Core::getCurrentDate(strtotime('tomorrow'))) + ->whereNull('raod.date_completed') + ) + ->orWhere( + fn (Builder $q) => + $q->where('raod.date_response_due', '<', Core::getCurrentDate(strtotime('tomorrow'))) + ->whereNull('raod.date_confirmed') + ) ) ); } if (is_array($this->assignedTo)) { - $q->whereIn('s.submission_id', fn (Builder $q) => + $q->whereIn( + 's.submission_id', + fn (Builder $q) => $q->select('s.submission_id') ->from('submissions AS s') - ->leftJoin('stage_assignments as sa', fn (Builder $q) => + ->leftJoin( + 'stage_assignments as sa', + fn (Builder $q) => $q->on('s.submission_id', '=', 'sa.submission_id') ->whereIn('sa.user_id', $this->assignedTo) ) - ->leftJoin('review_assignments as ra', fn (Builder $table) => + ->leftJoin( + 'review_assignments as ra', + fn (Builder $table) => $table->on('s.submission_id', '=', 'ra.submission_id') ->where('ra.declined', '=', (int) 0) ->where('ra.cancelled', '=', (int) 0) @@ -437,72 +461,89 @@ public function getQueryBuilder(): Builder // Search phrase if ($keywords->count()) { $likePattern = DB::raw("CONCAT('%', LOWER(?), '%')"); - if(!empty($this->assignedTo)) { + if (!empty($this->assignedTo)) { // Holds a single random row to check whether we have any assignment - $q->leftJoinSub(fn (Builder $q) => $q - ->from('review_assignments', 'ra') - ->whereIn('ra.reviewer_id', $this->assignedTo == self::UNASSIGNED ? [] : (array) $this->assignedTo) - ->select(DB::raw('1 AS value')) - ->limit(1), - 'any_assignment', 'any_assignment.value', '=', DB::raw('1') + $q->leftJoinSub( + fn (Builder $q) => $q + ->from('review_assignments', 'ra') + ->whereIn('ra.reviewer_id', $this->assignedTo == self::UNASSIGNED ? [] : (array) $this->assignedTo) + ->select(DB::raw('1 AS value')) + ->limit(1), + 'any_assignment', + 'any_assignment.value', + '=', + DB::raw('1') ); } // Builds the filters - $q->where(fn (Builder $q) => $keywords - ->map(fn (string $keyword) => $q - // Look for matches on the indexed data - ->orWhereExists(fn (Builder $query) => $query - ->from('submission_search_objects', 'sso') - ->join('submission_search_object_keywords AS ssok', 'sso.object_id', '=', 'ssok.object_id') - ->join('submission_search_keyword_list AS sskl', 'sskl.keyword_id', '=', 'ssok.keyword_id') - ->where('sskl.keyword_text', '=', DB::raw('LOWER(?)'))->addBinding($keyword) - ->whereColumn('s.submission_id', '=', 'sso.submission_id') - // Don't permit reviewers to search on author names - ->when(!empty($this->assignedTo), fn (Builder $q) => $q - ->where(fn (Builder $q) => $q - ->whereNull('any_assignment.value') - ->orWhere('sso.type', '!=', SubmissionSearch::SUBMISSION_SEARCH_AUTHOR) + $q->where( + fn (Builder $q) => $keywords + ->map( + fn (string $keyword) => $q + // Look for matches on the indexed data + ->orWhereExists( + fn (Builder $query) => $query + ->from('submission_search_objects', 'sso') + ->join('submission_search_object_keywords AS ssok', 'sso.object_id', '=', 'ssok.object_id') + ->join('submission_search_keyword_list AS sskl', 'sskl.keyword_id', '=', 'ssok.keyword_id') + ->where('sskl.keyword_text', '=', DB::raw('LOWER(?)'))->addBinding($keyword) + ->whereColumn('s.submission_id', '=', 'sso.submission_id') + // Don't permit reviewers to search on author names + ->when( + !empty($this->assignedTo), + fn (Builder $q) => $q + ->where( + fn (Builder $q) => $q + ->whereNull('any_assignment.value') + ->orWhere('sso.type', '!=', SubmissionSearch::SUBMISSION_SEARCH_AUTHOR) + ) + ) ) - ) - ) - // Search on the publication title - ->orWhereIn('s.submission_id', fn (Builder $query) => $query - ->select('p.submission_id')->from('publications AS p') - ->join('publication_settings AS ps', 'p.publication_id', '=', 'ps.publication_id') - ->where('ps.setting_name', '=', 'title') - ->where(DB::raw('LOWER(ps.setting_value)'), 'LIKE', $likePattern) - ->addBinding($keyword) - ) - // Search on the author name and ORCID - ->orWhereIn('s.submission_id', fn (Builder $query) => $query - ->select('p.submission_id') - ->from('publications AS p') - ->join('authors AS au', 'au.publication_id', '=', 'p.publication_id') - ->join('author_settings AS aus', 'aus.author_id', '=', 'au.author_id') - ->whereIn('aus.setting_name', [ - Identity::IDENTITY_SETTING_GIVENNAME, - Identity::IDENTITY_SETTING_FAMILYNAME, - 'orcid' - ]) - // Don't permit reviewers to search on author names - ->when(!empty($this->assignedTo), fn (Builder $q) => $q - ->where(fn (Builder $q) => $q - ->whereNull('any_assignment.value') - ->orWhereNotIn('aus.setting_name', [ - Identity::IDENTITY_SETTING_GIVENNAME, - Identity::IDENTITY_SETTING_FAMILYNAME - ]) + // Search on the publication title + ->orWhereIn( + 's.submission_id', + fn (Builder $query) => $query + ->select('p.submission_id')->from('publications AS p') + ->join('publication_settings AS ps', 'p.publication_id', '=', 'ps.publication_id') + ->where('ps.setting_name', '=', 'title') + ->where(DB::raw('LOWER(ps.setting_value)'), 'LIKE', $likePattern) + ->addBinding($keyword) + ) + // Search on the author name and ORCID + ->orWhereIn( + 's.submission_id', + fn (Builder $query) => $query + ->select('p.submission_id') + ->from('publications AS p') + ->join('authors AS au', 'au.publication_id', '=', 'p.publication_id') + ->join('author_settings AS aus', 'aus.author_id', '=', 'au.author_id') + ->whereIn('aus.setting_name', [ + Identity::IDENTITY_SETTING_GIVENNAME, + Identity::IDENTITY_SETTING_FAMILYNAME, + 'orcid' + ]) + // Don't permit reviewers to search on author names + ->when( + !empty($this->assignedTo), + fn (Builder $q) => $q + ->where( + fn (Builder $q) => $q + ->whereNull('any_assignment.value') + ->orWhereNotIn('aus.setting_name', [ + Identity::IDENTITY_SETTING_GIVENNAME, + Identity::IDENTITY_SETTING_FAMILYNAME + ]) + ) + ) + ->where(DB::raw('LOWER(aus.setting_value)'), 'LIKE', $likePattern) + ->addBinding($keyword) + ) + // Search for the exact submission ID + ->when( + ($numericWords = $keywords->filter(fn (string $keyword) => ctype_digit($keyword)))->count(), + fn (Builder $query) => $query->orWhereIn('s.submission_id', $numericWords) ) - ) - ->where(DB::raw('LOWER(aus.setting_value)'), 'LIKE', $likePattern) - ->addBinding($keyword) - ) - // Search for the exact submission ID - ->when( - ($numericWords = $keywords->filter(fn (string $keyword) => ctype_digit($keyword)))->count(), - fn (Builder $query) => $query->orWhereIn('s.submission_id', $numericWords) ) - ) ); } elseif (strlen($this->searchPhrase ?? '')) { // If there's search text, but no keywords could be extracted from it, force the query to return nothing