diff --git a/api/v1/_email/PKPEmailHandler.inc.php b/api/v1/_email/PKPEmailHandler.inc.php index 11353154691..44e21b6abf9 100644 --- a/api/v1/_email/PKPEmailHandler.inc.php +++ b/api/v1/_email/PKPEmailHandler.inc.php @@ -192,7 +192,7 @@ public function process(ServerRequestInterface $slimRequest, APIResponse $respon $countRunning = Capsule::table('jobs') ->where('queue', $args['queueId']) ->whereNotNull('reserved_at') - ->count(); + ->getCountForPagination(); $countPending = $this->countPending($args['queueId']); // Don't run another job if one is already running. @@ -230,6 +230,6 @@ function() { protected function countPending(string $queueId) : int { return Capsule::table('jobs') ->where('queue', $queueId) - ->count(); + ->getCountForPagination(); } } diff --git a/api/v1/stats/publications/PKPStatsPublicationHandler.inc.php b/api/v1/stats/publications/PKPStatsPublicationHandler.inc.php index 635f644a9ba..326a33f7a48 100644 --- a/api/v1/stats/publications/PKPStatsPublicationHandler.inc.php +++ b/api/v1/stats/publications/PKPStatsPublicationHandler.inc.php @@ -246,7 +246,7 @@ public function getMany($slimRequest, $response, $args) { $metricsDao = \DAORegistry::getDAO('MetricsDAO'); /** @var MetricsDAO */ return $response->withJson([ 'items' => $items, - 'itemsMax' => $metricsDao->countRecords($statsQO->toSql(), $statsQO->getBindings()), + 'itemsMax' => $metricsDao->countRecords($statsQO), ], 200); } diff --git a/classes/db/DAO.inc.php b/classes/db/DAO.inc.php index 47f68502bd2..6902f0304ba 100644 --- a/classes/db/DAO.inc.php +++ b/classes/db/DAO.inc.php @@ -29,6 +29,7 @@ define('SORT_DIRECTION_DESC', 0x00002); use Illuminate\Database\Capsule\Manager as Capsule; +use Illuminate\Database\Query\Builder; class DAO { /** @@ -98,11 +99,15 @@ function retrieveRange($sql, $params = [], $dbResultRange = null, $callHooks = t /** * Count the number of records in the supplied SQL statement (with optional bind parameters parameters) - * @param $sql string SQL query to be counted - * @param $params array Optional SQL query bind parameters + * @param $sql string|Builder SQL query to be counted + * @param $params array Optional SQL query bind parameters, only used when the $sql argument is a string * @return int */ public function countRecords($sql, $params = []) { + // In case a Laravel Builder has been received, drop its SELECT and ORDER BY clauses for optimization purposes + if ($sql instanceof Builder) { + return $sql->getCountForPagination(); + } $result = $this->retrieve('SELECT COUNT(*) AS row_count FROM (' . $sql . ') AS count_subquery', $params); return $result->current()->row_count; } diff --git a/classes/db/DAOResultFactory.inc.php b/classes/db/DAOResultFactory.inc.php index 15fd9345136..0482011abda 100644 --- a/classes/db/DAOResultFactory.inc.php +++ b/classes/db/DAOResultFactory.inc.php @@ -18,6 +18,7 @@ import('lib.pkp.classes.core.ItemIterator'); import('lib.pkp.classes.db.DAOResultIterator'); +use Illuminate\Database\Query\Builder; use Illuminate\Support\Enumerable; class DAOResultFactory extends ItemIterator { @@ -37,7 +38,7 @@ class DAOResultFactory extends ItemIterator { var $records; /** - * @var string|null Fetch SQL + * @var string|Builder|null Fetch SQL */ var $sql; @@ -63,7 +64,7 @@ class DAOResultFactory extends ItemIterator { * @param $dao object DAO class for factory * @param $functionName The function to call on $dao to create an object * @param $idFields array an array of primary key field names that uniquely identify a result row in the record set. Should be data object _data array key, not database column name - * @param $sql string Optional SQL query used to generate paged result set. Necessary when total row counts will be needed (e.g. when paging). WARNING: New code should not use this. + * @param $sql string|Builder Optional SQL query used to generate paged result set. Necessary when total row counts will be needed (e.g. when paging). WARNING: New code should not use this. * @param $params array Optional parameters for SQL query used to generate paged result set. Necessary when total row counts will be needed (e.g. when paging). WARNING: New code should not use this. * @param $rangeInfo DBResultRange Optional pagination information. WARNING: New code should not use this. */ diff --git a/classes/log/EmailLogDAO.inc.php b/classes/log/EmailLogDAO.inc.php index 06a6dc615a6..08fc36d681a 100644 --- a/classes/log/EmailLogDAO.inc.php +++ b/classes/log/EmailLogDAO.inc.php @@ -59,19 +59,22 @@ function _getByEventType($assocType, $assocId, $eventType, $userId = null, $rang ]; if ($userId) $params[] = $userId; - $result = $this->retrieveRange( - $sql = 'SELECT e.* - FROM email_log e' . - ($userId ? ' LEFT JOIN email_log_users u ON e.log_id = u.email_log_id' : '') . - ' WHERE e.assoc_type = ? AND + $baseSql = ' + FROM email_log e' . + ($userId ? ' LEFT JOIN email_log_users u ON e.log_id = u.email_log_id' : '') . ' + WHERE e.assoc_type = ? AND e.assoc_id = ? AND e.event_type = ?' . - ($userId ? ' AND u.user_id = ?' : ''), + ($userId ? ' AND u.user_id = ?' : '') . ' + '; + + $result = $this->retrieveRange( + "SELECT e.* {$baseSql}", $params, $rangeInfo ); - return new DAOResultFactory($result, $this, 'build', [], $sql, $params, $rangeInfo); // Counted in submissionEmails.tpl + return new DAOResultFactory($result, $this, 'build', [], "SELECT 0 {$baseSql}", $params, $rangeInfo); // Counted in submissionEmails.tpl } /** diff --git a/classes/migration/upgrade/PKPv3_3_0UpgradeMigration.inc.php b/classes/migration/upgrade/PKPv3_3_0UpgradeMigration.inc.php index c42c5de4e18..0e30761791a 100755 --- a/classes/migration/upgrade/PKPv3_3_0UpgradeMigration.inc.php +++ b/classes/migration/upgrade/PKPv3_3_0UpgradeMigration.inc.php @@ -491,7 +491,7 @@ function (Builder $q) use ($row, $lastInsertedFileId) { // be unique. $count = Capsule::table('review_round_files') ->where('file_id', '=', $row->file_id) - ->count(); + ->getCountForPagination(); if ($count > 1) { Capsule::table('review_round_files') ->where('file_id', '=', $row->file_id) diff --git a/classes/note/NoteDAO.inc.php b/classes/note/NoteDAO.inc.php index b867f0d2654..8788ac57eff 100644 --- a/classes/note/NoteDAO.inc.php +++ b/classes/note/NoteDAO.inc.php @@ -89,18 +89,19 @@ function getByAssoc($assocType, $assocId, $userId = null, $orderBy = NOTE_ORDER_ $directionSanitized = 'DESC'; } - $result = $this->retrieve( - $sql = 'SELECT * - FROM notes - WHERE assoc_id = ? + $baseSql = ' + FROM notes + WHERE assoc_id = ? AND assoc_type = ? ' . ($userId?' AND user_id = ?':'') . - ($isAdmin?'':' - AND (title IS NOT NULL OR contents IS NOT NULL)') . ' - ORDER BY ' . $orderSanitized . ' ' . $directionSanitized, + ($isAdmin?'':' AND (title IS NOT NULL OR contents IS NOT NULL)') . ' + '; + + $result = $this->retrieve( + "SELECT * {$baseSql} ORDER BY {$orderSanitized} {$directionSanitized}", $params ); - return new DAOResultFactory($result, $this, '_fromRow', [], $sql, $params); // Counted in QueriesGridCellProvider + return new DAOResultFactory($result, $this, '_fromRow', [], "SELECT 0 {$baseSql}", $params); // Counted in QueriesGridCellProvider } /** diff --git a/classes/security/UserGroupDAO.inc.php b/classes/security/UserGroupDAO.inc.php index f86393c8b75..e782f98a2b4 100644 --- a/classes/security/UserGroupDAO.inc.php +++ b/classes/security/UserGroupDAO.inc.php @@ -250,18 +250,21 @@ function isDefault($userGroupId) { function getByRoleId($contextId, $roleId, $default = false, $dbResultRange = null) { $params = [(int) $contextId, (int) $roleId]; if ($default) $params[] = 1; // true - $result = $this->retrieveRange( - $sql = 'SELECT * - FROM user_groups - WHERE context_id = ? AND + + $baseSql = ' + FROM user_groups + WHERE context_id = ? AND role_id = ? - ' . ($default?' AND is_default = ?':'') - . ' ORDER BY user_group_id', + ' . ($default?' AND is_default = ?':'') . ' + '; + + $result = $this->retrieveRange( + "SELECT * {$baseSql} ORDER BY user_group_id", $params, $dbResultRange ); - return new DAOResultFactory($result, $this, '_returnFromRow', [], $sql, $params, $dbResultRange); + return new DAOResultFactory($result, $this, '_returnFromRow', [], "SELECT 0 {$baseSql}", $params, $dbResultRange); } /** @@ -381,15 +384,18 @@ function getByContextId($contextId = null, $dbResultRange = null) { $params = []; if ($contextId) $params[] = (int) $contextId; + $baseSql = ' + FROM user_groups ug' . + ($contextId?' WHERE ug.context_id = ?':'') . ' + '; + $result = $this->retrieveRange( - $sql = 'SELECT ug.* - FROM user_groups ug' . - ($contextId?' WHERE ug.context_id = ?':''), + "SELECT ug.* {$baseSql}", $params, $dbResultRange ); - return new DAOResultFactory($result, $this, '_returnFromRow', [], $sql, $params, $dbResultRange); + return new DAOResultFactory($result, $this, '_returnFromRow', [], "SELECT 0 {$baseSql}", $params, $dbResultRange); } /** @@ -509,14 +515,15 @@ function getUsersById($userGroupId = null, $contextId = null, $searchType = null COALESCE(us.setting_value, '') = '', us.locale <> ? LIMIT 1 )"; - $params = [ + $selectParams = [ IDENTITY_SETTING_GIVENNAME, $locale, $primaryLocale, $locale, IDENTITY_SETTING_FAMILYNAME, $locale, $primaryLocale, $locale ]; - $sql = "SELECT u.*, $settingValue AS user_given, $settingValue AS user_family + $baseSql = ' FROM users AS u - WHERE 1 = 1"; + WHERE 1 = 1 + '; // Has user group if ($contextId || $userGroupId) { @@ -526,7 +533,7 @@ function getUsersById($userGroupId = null, $contextId = null, $searchType = null if ($userGroupId) { $params[] = (int) $userGroupId; } - $sql .= ' AND EXISTS ( + $baseSql .= ' AND EXISTS ( SELECT 0 FROM user_user_groups uug INNER JOIN user_groups ug @@ -537,12 +544,16 @@ function getUsersById($userGroupId = null, $contextId = null, $searchType = null ' . ($userGroupId ? 'AND ug.user_group_id = ?' : '') . ' )'; } - $sql .= ' ' . $this->_getSearchSql($searchType, $search, $searchMatch, $params); + $baseSql .= ' ' . $this->_getSearchSql($searchType, $search, $searchMatch, $params); // Get the result set - $result = $this->retrieveRange($sql, $params, $dbResultRange); + $result = $this->retrieveRange( + "SELECT u.*, $settingValue AS user_given, $settingValue AS user_family {$baseSql} " . $this->userDao->getOrderBy(), + array_merge($selectParams, $params), + $dbResultRange + ); - return new DAOResultFactory($result, $this->userDao, '_returnUserFromRowWithData', [], $sql, $params, $dbResultRange); + return new DAOResultFactory($result, $this->userDao, '_returnUserFromRowWithData', [], "SELECT 0 {$baseSql}", $params, $dbResultRange); } // @@ -910,8 +921,6 @@ function _getSearchSql($searchType, $search, $searchMatch, &$params) { } } - $searchSql .= $this->userDao->getOrderBy(); // FIXME Add "sort field" parameter? - return $searchSql; } @@ -930,22 +939,25 @@ function _getSearchSql($searchType, $search, $searchMatch, &$params) { function getUserGroupsByStage($contextId, $stageId, $roleId = null, $dbResultRange = null) { $params = [(int) $contextId, (int) $stageId]; if ($roleId) $params[] = (int) $roleId; + + $baseSql = ' + FROM user_groups ug + JOIN user_group_stage ugs ON (ug.user_group_id = ugs.user_group_id AND ug.context_id = ugs.context_id) + WHERE ugs.context_id = ? AND + ugs.stage_id = ? + ' . ($roleId?'AND ug.role_id = ?':'') . ' + '; + return new DAOResultFactory( $this->retrieveRange( - $sql = 'SELECT ug.* - FROM user_groups ug - JOIN user_group_stage ugs ON (ug.user_group_id = ugs.user_group_id AND ug.context_id = ugs.context_id) - WHERE ugs.context_id = ? AND - ugs.stage_id = ? - ' . ($roleId?'AND ug.role_id = ?':'') . ' - ORDER BY ug.role_id ASC', + "SELECT ug.* {$baseSql} ORDER BY ug.role_id ASC", $params, $dbResultRange ), $this, '_returnFromRow', [], - $sql, $params, $dbResultRange + "SELECT 0 {$baseSql}", $params, $dbResultRange ); } diff --git a/classes/services/PKPSubmissionService.inc.php b/classes/services/PKPSubmissionService.inc.php index ade3ae72a38..b8fb44dad65 100644 --- a/classes/services/PKPSubmissionService.inc.php +++ b/classes/services/PKPSubmissionService.inc.php @@ -102,8 +102,8 @@ public function getMany($args = []) { if (isset($args['offset'])) unset($args['offset']); $submissionListQO = $this->getQueryBuilder($args)->getQuery(); $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */ - $result = $submissionDao->retrieveRange($sql = $submissionListQO->toSql(), $params = $submissionListQO->getBindings(), $range); - $queryResults = new DAOResultFactory($result, $submissionDao, '_fromRow', [], $sql, $params, $range); + $result = $submissionDao->retrieveRange($submissionListQO->toSql(), $submissionListQO->getBindings(), $range); + $queryResults = new DAOResultFactory($result, $submissionDao, '_fromRow', [], $submissionListQO, [], $range); return $queryResults->toIterator(); } diff --git a/classes/services/PKPUserService.inc.php b/classes/services/PKPUserService.inc.php index f34791723ee..b49ac050db5 100644 --- a/classes/services/PKPUserService.inc.php +++ b/classes/services/PKPUserService.inc.php @@ -83,7 +83,7 @@ public function getMany($args = []) { $userListQO = $this->getQueryBuilder($args)->getQuery(); $userDao = DAORegistry::getDAO('UserDAO'); /* @var $userDao UserDAO */ $result = $userDao->retrieveRange($userListQO->toSql(), $userListQO->getBindings(), $range); - $queryResults = new DAOResultFactory($result, $userDao, '_returnUserFromRowWithData', [], $userListQO->toSql(), $userListQO->getBindings()); + $queryResults = new DAOResultFactory($result, $userDao, '_returnUserFromRowWithData', [], $userListQO); return $queryResults->toIterator(); } @@ -592,8 +592,9 @@ public function getAccessibleWorkflowStages($userId, $contextId, &$submission, $ * @param array $args See self::getMany() */ public function count($args = []) { - $qb = $this->getQueryBuilder($args); - return $qb->getQuery()->get()->count(); + return $this->getQueryBuilder($args) + ->getQuery() + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPAnnouncementQueryBuilder.inc.php b/classes/services/queryBuilders/PKPAnnouncementQueryBuilder.inc.php index c3c98e492f6..dbefdc1aa1c 100644 --- a/classes/services/queryBuilders/PKPAnnouncementQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPAnnouncementQueryBuilder.inc.php @@ -70,9 +70,7 @@ public function searchPhrase($phrase) { public function getCount() { return $this ->getQuery() - ->select('a.announcement_id') - ->get() - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPAuthorQueryBuilder.inc.php b/classes/services/queryBuilders/PKPAuthorQueryBuilder.inc.php index c7622ca2ace..43c87233597 100644 --- a/classes/services/queryBuilders/PKPAuthorQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPAuthorQueryBuilder.inc.php @@ -102,9 +102,7 @@ public function filterByPublicationIds($publicationIds) { public function getCount() { return $this ->getQuery() - ->select('a.author_id') - ->get() - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPContextQueryBuilder.inc.php b/classes/services/queryBuilders/PKPContextQueryBuilder.inc.php index acc9643e235..ff9a348caad 100644 --- a/classes/services/queryBuilders/PKPContextQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPContextQueryBuilder.inc.php @@ -85,9 +85,7 @@ public function searchPhrase($phrase) { public function getCount() { return $this ->getQuery() - ->select('c.' . $this->dbIdColumn) - ->get() - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPEmailTemplateQueryBuilder.inc.php b/classes/services/queryBuilders/PKPEmailTemplateQueryBuilder.inc.php index ddfcfc684cd..c664b8d79a8 100644 --- a/classes/services/queryBuilders/PKPEmailTemplateQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPEmailTemplateQueryBuilder.inc.php @@ -179,7 +179,7 @@ public function getCount() { $compiledQuery = $this->getCompiledQuery(); return Capsule::table(Capsule::raw('(' . $compiledQuery[0] . ') as email_template_count')) ->setBindings($compiledQuery[1]) - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPPublicationQueryBuilder.inc.php b/classes/services/queryBuilders/PKPPublicationQueryBuilder.inc.php index 3495be43a50..0682a8d1e73 100644 --- a/classes/services/queryBuilders/PKPPublicationQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPPublicationQueryBuilder.inc.php @@ -85,9 +85,7 @@ public function offsetBy($offset) { public function getCount() { return $this ->getQuery() - ->select('p.publication_id') - ->get() - ->count(); + ->getCountForPagination(); } /** @@ -188,6 +186,6 @@ public function isDuplicateUrlPath($urlPath, $submissionId, $contextId) { ->where('url_path', '=' , $urlPath) ->where('p.submission_id', '!=', $submissionId) ->where('s.context_id', '=', $contextId) - ->count(); + ->getCountForPagination(); } } diff --git a/classes/services/queryBuilders/PKPStatsEditorialQueryBuilder.inc.php b/classes/services/queryBuilders/PKPStatsEditorialQueryBuilder.inc.php index 283dc150909..0d08c3ebe82 100644 --- a/classes/services/queryBuilders/PKPStatsEditorialQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPStatsEditorialQueryBuilder.inc.php @@ -95,7 +95,7 @@ public function countSubmissionsReceived() { $q->where('s.date_submitted', '<=', $this->dateEnd); } - return $q->count(); + return $q->getCountForPagination(); } /** @@ -165,7 +165,7 @@ public function countByDecisions($decisions, $forSubmittedDate = false) { public function countByStatus($status) { return $this->_getObject() ->whereIn('s.status', (array) $status) - ->count(); + ->getCountForPagination(); } /** @@ -180,7 +180,7 @@ public function countActiveByStages($stages) { return $this->_getObject() ->where('s.status', '=', STATUS_QUEUED) ->whereIn('s.stage_id', $stages) - ->count(); + ->getCountForPagination(); } /** @@ -214,7 +214,7 @@ public function countPublished() { } } - return $q->count(); + return $q->getCountForPagination(); } /** @@ -433,7 +433,7 @@ public function countImported() { ->when($this->dateEnd, function (Builder $q) { $q->where('s.date_submitted', '<=', $this->dateEnd); }) - ->count(); + ->getCountForPagination(); } /** @@ -451,7 +451,7 @@ public function countInProgress() { ->when($this->dateEnd, function (Builder $q) { $q->where('s.date_submitted', '<=', $this->dateEnd); }) - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPSubmissionFileQueryBuilder.inc.php b/classes/services/queryBuilders/PKPSubmissionFileQueryBuilder.inc.php index be70fba8ffa..2ce0f53df3f 100644 --- a/classes/services/queryBuilders/PKPSubmissionFileQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPSubmissionFileQueryBuilder.inc.php @@ -159,9 +159,7 @@ public function includeDependentFiles($includeDependentFiles) { public function getCount() { return $this ->getQuery() - ->select('sf.submission_file_id') - ->get() - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPSubmissionQueryBuilder.inc.php b/classes/services/queryBuilders/PKPSubmissionQueryBuilder.inc.php index a528edc8b57..eebf365e2b9 100644 --- a/classes/services/queryBuilders/PKPSubmissionQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPSubmissionQueryBuilder.inc.php @@ -239,9 +239,7 @@ public function offsetBy($offset) { public function getCount() { return $this ->getQuery() - ->select('s.submission_id') - ->get() - ->count(); + ->getCountForPagination(); } /** diff --git a/classes/services/queryBuilders/PKPUserQueryBuilder.inc.php b/classes/services/queryBuilders/PKPUserQueryBuilder.inc.php index a6c5e9588a8..6455ac36ad9 100644 --- a/classes/services/queryBuilders/PKPUserQueryBuilder.inc.php +++ b/classes/services/queryBuilders/PKPUserQueryBuilder.inc.php @@ -424,12 +424,9 @@ public function offsetBy($offset) { * @copydoc PKP\Services\QueryBuilders\Interfaces\EntityQueryBuilderInterface::getCount() */ public function getCount() { - $q = $this->getQuery(); - // Reset the orderBy - $q->orders = []; - return $q->select('u.user_id') - ->get() - ->count(); + return $this + ->getQuery() + ->getCountForPagination(); } /** diff --git a/classes/submission/SubmissionCommentDAO.inc.php b/classes/submission/SubmissionCommentDAO.inc.php index 307be399821..fd150913191 100644 --- a/classes/submission/SubmissionCommentDAO.inc.php +++ b/classes/submission/SubmissionCommentDAO.inc.php @@ -72,19 +72,19 @@ function getReviewerCommentsByReviewerId($submissionId, $reviewerId = null, $rev $params = array((int) $submissionId); if ($reviewerId) $params[] = (int) $reviewerId; if ($reviewId) $params[] = (int) $reviewId; + + $baseSql = ' + FROM submission_comments a + WHERE submission_id = ? + ' . ($reviewerId?' AND author_id = ?':'') . ' + ' . ($reviewId?' AND assoc_id = ?':'') . ' + ' . ($viewable === true?' AND viewable = 1':'') . ' + ' . ($viewable === false?' AND viewable = 0':'') . ' + '; + return new DAOResultFactory( - $this->retrieve( - $sql = 'SELECT a.* - FROM submission_comments a - WHERE submission_id = ? - ' . ($reviewerId?' AND author_id = ?':'') . ' - ' . ($reviewId?' AND assoc_id = ?':'') . ' - ' . ($viewable === true?' AND viewable = 1':'') . ' - ' . ($viewable === false?' AND viewable = 0':'') . ' - ORDER BY date_posted DESC', - $params - ), - $this, '_fromRow', [], $sql, $params // Counted in readReview.tpl and authorReadReview.tpl + $this->retrieve("SELECT a.* {$baseSql} ORDER BY date_posted DESC", $params), + $this, '_fromRow', [], "SELECT 0 {$baseSql}", $params // Counted in readReview.tpl and authorReadReview.tpl ); } diff --git a/classes/user/UserDAO.inc.php b/classes/user/UserDAO.inc.php index e13dee667bf..eee24445743 100644 --- a/classes/user/UserDAO.inc.php +++ b/classes/user/UserDAO.inc.php @@ -137,7 +137,7 @@ function getUserByCredentials($username, $password, $allowDisabled = true) { * @return DAOResultFactory containing matching Users */ function getReviewersForSubmission($contextId, $submissionId, $round) { - return new DAOResultFactory($result, + return new DAOResultFactory( $this->retrieve( 'SELECT u.* , ' . $this->getFetchColumns() . ' @@ -156,8 +156,7 @@ function getReviewersForSubmission($contextId, $submissionId, $round) { ROLE_ID_REVIEWER, (int) $submissionId, (int) $round - ]), - $params + ]) ), $this, '_returnUserFromRowWithData' ); diff --git a/classes/user/UserStageAssignmentDAO.inc.php b/classes/user/UserStageAssignmentDAO.inc.php index bd593340a4b..9e79fd781b5 100644 --- a/classes/user/UserStageAssignmentDAO.inc.php +++ b/classes/user/UserStageAssignmentDAO.inc.php @@ -106,31 +106,34 @@ function filterUsersNotAssignedToStageInUserGroup($submissionId, $stageId, $user if ($name !== null) { $params = array_merge($params, array_fill(0, 6, (string) $name)); } - $result = $this->retrieveRange( - $sql = 'SELECT u.* - FROM users u - LEFT JOIN user_user_groups uug ON (u.user_id = uug.user_id) - LEFT JOIN stage_assignments s ON (s.user_id = uug.user_id AND s.user_group_id = uug.user_group_id AND s.submission_id = ?) - JOIN user_group_stage ugs ON (uug.user_group_id = ugs.user_group_id AND ugs.stage_id = ?) - LEFT JOIN user_settings usgs_pl ON (usgs_pl.user_id = u.user_id AND usgs_pl.setting_name = ? AND usgs_pl.locale = ?) - LEFT JOIN user_settings usfs_pl ON (usfs_pl.user_id = u.user_id AND usfs_pl.setting_name = ? AND usfs_pl.locale = ?) - LEFT JOIN user_settings usgs_l ON (usgs_l.user_id = u.user_id AND usgs_l.setting_name = ? AND usgs_l.locale = ?) - LEFT JOIN user_settings usfs_l ON (usfs_l.user_id = u.user_id AND usfs_l.setting_name = ? AND usfs_l.locale = ?) - WHERE uug.user_group_id = ? AND + $baseSql = ' + FROM users u + LEFT JOIN user_user_groups uug ON (u.user_id = uug.user_id) + LEFT JOIN stage_assignments s ON (s.user_id = uug.user_id AND s.user_group_id = uug.user_group_id AND s.submission_id = ?) + JOIN user_group_stage ugs ON (uug.user_group_id = ugs.user_group_id AND ugs.stage_id = ?) + LEFT JOIN user_settings usgs_pl ON (usgs_pl.user_id = u.user_id AND usgs_pl.setting_name = ? AND usgs_pl.locale = ?) + LEFT JOIN user_settings usfs_pl ON (usfs_pl.user_id = u.user_id AND usfs_pl.setting_name = ? AND usfs_pl.locale = ?) + LEFT JOIN user_settings usgs_l ON (usgs_l.user_id = u.user_id AND usgs_l.setting_name = ? AND usgs_l.locale = ?) + LEFT JOIN user_settings usfs_l ON (usfs_l.user_id = u.user_id AND usfs_l.setting_name = ? AND usfs_l.locale = ?) + WHERE uug.user_group_id = ? AND s.user_group_id IS NULL' - . ($name !== null - ? " AND (LOWER(usgs_pl.setting_value) LIKE CONCAT('%', LOWER(?), '%') - OR LOWER(usgs_l.setting_value) LIKE CONCAT('%', LOWER(?), '%') - OR LOWER(usfs_pl.setting_value) LIKE CONCAT('%', LOWER(?), '%') - OR LOWER(usfs_l.setting_value) LIKE CONCAT('%', LOWER(?), '%') - OR LOWER(u.username) LIKE CONCAT('%', LOWER(?), '%') - OR LOWER(u.email) LIKE CONCAT('%', LOWER(?), '%'))" - : "") - . " ORDER BY COALESCE(usfs_l.setting_value, usfs_pl.setting_value)", - $params, - $rangeInfo); - return new DAOResultFactory($result, $this, '_returnUserFromRowWithData', [], $sql, $params, $rangeInfo); + . ($name !== null + ? " AND (LOWER(usgs_pl.setting_value) LIKE CONCAT('%', LOWER(?), '%') + OR LOWER(usgs_l.setting_value) LIKE CONCAT('%', LOWER(?), '%') + OR LOWER(usfs_pl.setting_value) LIKE CONCAT('%', LOWER(?), '%') + OR LOWER(usfs_l.setting_value) LIKE CONCAT('%', LOWER(?), '%') + OR LOWER(u.username) LIKE CONCAT('%', LOWER(?), '%') + OR LOWER(u.email) LIKE CONCAT('%', LOWER(?), '%'))" + : "") . ' + '; + + $result = $this->retrieveRange( + "SELECT u.* {$baseSql} ORDER BY COALESCE(usfs_l.setting_value, usfs_pl.setting_value)", + $params, + $rangeInfo + ); + return new DAOResultFactory($result, $this, '_returnUserFromRowWithData', [], "SELECT 0 {$baseSql}", $params, $rangeInfo); } } diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 6a5a766d97e..f502784818c 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -315,6 +315,7 @@ Cypress.Commands.add('assignParticipant', (role, name, recommendOnly) => { cy.get('select[name=filterUserGroupId').select(role); cy.get('input[id^="namegrid-users-userselect-userselectgrid-"]').type(names[1], {delay: 0}); cy.get('form[id="searchUserFilter-grid-users-userselect-userselectgrid"]').find('button[id^="submitFormButton-"]').click(); + cy.waitJQuery(); cy.get('input[name="userId"]').click(); // Assume only one user results from the search. if (recommendOnly) cy.get('input[name="recommendOnly"]').click(); cy.flushNotifications(); @@ -394,8 +395,14 @@ Cypress.Commands.add('createUser', user => { user.roles.forEach(role => { cy.get('form[id=userRoleForm]').contains(role).click(); }); - cy.get('form[id=userRoleForm] button[id^=submitFormButton]').click(); - cy.get('span[id$="-username"]:contains("' + Cypress.$.escapeSelector(user.username) + '")'); + cy.server(); + cy.route('POST', '**/grid/settings/user/user-grid/update-user-roles*').as('rolesSaved'); + cy.get('div[id^=component-grid-settings-user-usergrid]').as('userGrid').then(staleUserGrid => { + cy.get('form[id=userRoleForm] button[id^=submitFormButton]').click(); + cy.wait('@rolesSaved').its('status').should('eq', 200); + // Wait for the interface to refresh, the "User Grid" will be recreated and get a new ID. + cy.get('@userGrid').should('not.have.attr', 'id', staleUserGrid.attr('id')); + }); }); Cypress.Commands.add('flushNotifications', function() {