/** * Returns group members * * @return {Integer[]} Array of userIDs */ public function getMembers() { if (!$this->exists()) { return array(); } $sql = "SELECT userID FROM groupUsers WHERE groupID=? AND role='member'"; $ids = Zotero_DB::columnQuery($sql, $this->id); if (!$ids) { return array(); } $ids = Zotero_Users::getValidUsers($ids); return $ids; }
public static function getAllAdvanced($userID = false, $params = array(), $permissions = null) { $buffer = 20; $maxTimes = 3; $groups = array(); $start = !empty($params['start']) ? $params['start'] : 0; $limit = !empty($params['limit']) ? $params['limit'] + $buffer : false; $totalResults = null; $times = 0; while (true) { if ($times > 0) { Z_Core::logError('Getting more groups in Zotero_Groups::getAllAdvanced()'); } $sql = "SELECT SQL_CALC_FOUND_ROWS G.groupID, GUO.userID AS ownerUserID FROM groups G\n\t\t\t\t\tJOIN groupUsers GUO ON (G.groupID=GUO.groupID AND GUO.role='owner') "; $sqlParams = array(); if ($userID) { $sql .= "JOIN groupUsers GUA ON (G.groupID=GUA.groupID) WHERE GUA.userID=? "; $sqlParams[] = $userID; } $paramSQL = ""; $includeEmpty = false; if (!empty($params['q'])) { if (!is_array($params['q'])) { $params['q'] = array($params['q']); } foreach ($params['q'] as $q) { $field = explode(":", $q); if (sizeOf($field) == 2) { switch ($field[0]) { case 'slug': $includeEmpty = true; break; default: throw new Exception("Cannot search by group field '{$field[0]}'", Z_ERROR_INVALID_GROUP_TYPE); } $paramSQL .= "AND " . $field[0]; // If first character is '-', negate $paramSQL .= $field[0][0] == '-' ? '!' : ''; $paramSQL .= "=? "; $sqlParams[] = $field[1]; } else { $paramSQL .= "AND name LIKE ? "; $sqlParams[] = "%{$q}%"; } } } if (!$userID) { if ($includeEmpty) { $sql .= "WHERE 1 "; } else { // Don't include groups that have never had items $sql .= "JOIN libraries L ON (G.libraryID=L.libraryID)\n\t\t\t\t\t\t\tWHERE L.lastUpdated != '0000-00-00 00:00:00' "; } } $sql .= $paramSQL; if (!empty($params['fq'])) { if (!is_array($params['fq'])) { $params['fq'] = array($params['fq']); } foreach ($params['fq'] as $fq) { $facet = explode(":", $fq); if (sizeOf($facet) == 2 && preg_match('/-?GroupType/', $facet[0])) { switch ($facet[1]) { case 'PublicOpen': case 'PublicClosed': case 'Private': break; default: throw new Exception("Invalid group type '{$facet[1]}'", Z_ERROR_INVALID_GROUP_TYPE); } $sql .= "AND type"; // If first character is '-', negate $sql .= $facet[0][0] == '-' ? '!' : ''; $sql .= "=? "; $sqlParams[] = $facet[1]; } } } if (!empty($params['order'])) { $order = $params['order']; if ($order == 'title') { $order = 'name'; } $sql .= "ORDER BY {$order}"; if (!empty($params['sort'])) { $sql .= " " . $params['sort'] . " "; } } // Set limit higher than the actual limit, in case some groups are // removed during access checks // // Actual limiting is done below if ($limit) { $sql .= "LIMIT ?, ?"; $sqlParams[] = $start; $sqlParams[] = $limit; } $rows = Zotero_DB::query($sql, $sqlParams); if (!$rows) { break; } if (!$totalResults) { $foundRows = Zotero_DB::valueQuery("SELECT FOUND_ROWS()"); $totalResults = $foundRows; } // Include only groups with non-banned owners $owners = array(); foreach ($rows as $row) { $owners[] = $row['ownerUserID']; } $owners = Zotero_Users::getValidUsers($owners); $ids = array(); foreach ($rows as $row) { if (!in_array($row['ownerUserID'], $owners)) { $totalResults--; continue; } $ids[] = $row['groupID']; } $batchStartPos = sizeOf($groups); foreach ($ids as $id) { $group = Zotero_Groups::get($id, true); $groups[] = $group; } // Remove groups that can't be accessed if ($permissions) { for ($i = $batchStartPos; $i < sizeOf($groups); $i++) { $libraryID = (int) $groups[$i]->libraryID; // TEMP: casting shouldn't be necessary if (!$permissions->canAccess($libraryID)) { array_splice($groups, $i, 1); $i--; $totalResults--; } } } $times++; if ($times == $maxTimes) { Z_Core::logError('Too many queries in Zotero_Groups::getAllAdvanced()'); break; } if (empty($params['limit'])) { break; } // If we have enough groups to fill the limit, stop if (sizeOf($groups) > $params['limit']) { break; } // If there no more rows, stop if ($start + sizeOf($rows) == $foundRows) { break; } // This shouldn't happen if ($start + sizeOf($rows) > $foundRows) { Z_Core::logError('More rows than $foundRows in Zotero_Groups::getAllAdvanced()'); } $start = $start + sizeOf($rows); // Get number we still need plus the buffer or all remaining, whichever is lower $limit = min($params['limit'] - sizeOf($groups) + $buffer, $foundRows - $start); } // TODO: generate previous start value if (!$groups) { return array('groups' => array(), 'totalResults' => 0); } // Fake limiting -- we can't just use SQL limit because // some groups might be inaccessible if (!empty($params['limit'])) { $groups = array_slice($groups, 0, $params['limit']); } $results = array('groups' => $groups, 'totalResults' => $totalResults); return $results; }
public static function getAllAdvanced($userID = false, $params = array(), $permissions = null) { $buffer = 20; $maxTimes = 3; $groups = array(); $start = !empty($params['start']) ? $params['start'] : 0; $limit = !empty($params['limit']) ? $params['limit'] + $buffer : false; $totalResults = null; $times = 0; while (true) { if ($times > 0) { Z_Core::logError('Getting more groups in Zotero_Groups::getAllAdvanced()'); } $calcFoundRows = !$totalResults; $cacheFoundRows = $calcFoundRows && !$userID; // If we don't yet have a row count and this isn't a user-specific search, // try to get a cached row count. if ($cacheFoundRows) { $foundRowsCacheKey = self::getCacheComponentFromParam($params, 'q') . "," . self::getCacheComponentFromParam($params, 'fq'); $foundRowsTTL = 180; $foundRowsLockTTL = 10; $foundRowsRealTTL = 3600; $obj = Z_Core::$MC->get($foundRowsCacheKey); if ($obj) { $foundRows = $obj['rows']; $exp = $obj['exp']; // If count was found but is past the expiration time, check if another // request is getting the row count, and fetch it if not if ($exp < time()) { if (!Z_Core::$MC->add($foundRowsCacheKey . "Lock", true, $foundRowsLockTTL)) { $calcFoundRows = false; } } else { $calcFoundRows = false; } } } $sql = "SELECT " . ($calcFoundRows ? "SQL_CALC_FOUND_ROWS " : "") . "G.groupID, GUO.userID AS ownerUserID FROM groups G " . "JOIN groupUsers GUO ON (G.groupID=GUO.groupID AND GUO.role='owner') "; $sqlParams = array(); if ($userID) { $sql .= "JOIN groupUsers GUA ON (G.groupID=GUA.groupID) WHERE GUA.userID=? "; $sqlParams[] = $userID; } $paramSQL = ""; $includeEmpty = false; if (!empty($params['q'])) { if (!is_array($params['q'])) { $params['q'] = array($params['q']); } foreach ($params['q'] as $q) { $field = explode(":", $q); if (sizeOf($field) == 2) { switch ($field[0]) { case 'slug': $includeEmpty = true; break; default: throw new Exception("Cannot search by group field '{$field[0]}'", Z_ERROR_INVALID_GROUP_TYPE); } $paramSQL .= "AND " . $field[0]; // If first character is '-', negate $paramSQL .= $field[0][0] == '-' ? '!' : ''; $paramSQL .= "=? "; $sqlParams[] = $field[1]; } else { $paramSQL .= "AND name LIKE ? "; $sqlParams[] = "%{$q}%"; } } } if (!$userID) { if ($includeEmpty) { $sql .= "WHERE 1 "; } else { // Don't include groups that have never had items $sql .= "JOIN libraries L ON (G.libraryID=L.libraryID)\n\t\t\t\t\t\t\tWHERE L.lastUpdated != '0000-00-00 00:00:00' "; } } $sql .= $paramSQL; if (!empty($params['fq'])) { if (!is_array($params['fq'])) { $params['fq'] = array($params['fq']); } foreach ($params['fq'] as $fq) { $facet = explode(":", $fq); if (sizeOf($facet) == 2 && preg_match('/-?GroupType/', $facet[0])) { switch ($facet[1]) { case 'PublicOpen': case 'PublicClosed': case 'Private': break; default: throw new Exception("Invalid group type '{$facet[1]}'", Z_ERROR_INVALID_GROUP_TYPE); } $sql .= "AND type"; // If first character is '-', negate $sql .= $facet[0][0] == '-' ? '!' : ''; $sql .= "=? "; $sqlParams[] = $facet[1]; } } } if (!empty($params['sort'])) { $order = $params['sort']; if ($order == 'title') { $order = 'name'; } $sql .= "ORDER BY {$order}"; if (!empty($params['direction'])) { $sql .= " " . $params['direction'] . " "; } } // Limit is set $buffer higher than the actual limit, in case some groups are // removed during access checks // // Actual limiting is done below if ($limit) { $sql .= "LIMIT ?, ?"; $sqlParams[] = $start; $sqlParams[] = $limit; } $rows = Zotero_DB::query($sql, $sqlParams); if (!$rows) { break; } if (is_null($totalResults)) { if ($calcFoundRows) { $foundRows = Zotero_DB::valueQuery("SELECT FOUND_ROWS()"); // Cache found rows count, and store earlier expiration time so that one // request can trigger a recalculation before cached value expires if ($cacheFoundRows) { Z_Core::$MC->set($foundRowsCacheKey, ['rows' => $foundRows, 'exp' => time() + $foundRowsTTL], $foundRowsRealTTL); } } $totalResults = $foundRows; } // Include only groups with non-banned owners $owners = array(); foreach ($rows as $row) { $owners[] = $row['ownerUserID']; } $owners = Zotero_Users::getValidUsers($owners); $ids = array(); foreach ($rows as $row) { if (!in_array($row['ownerUserID'], $owners)) { $totalResults--; continue; } $ids[] = $row['groupID']; } $batchStartPos = sizeOf($groups); foreach ($ids as $id) { $group = Zotero_Groups::get($id, true); $groups[] = $group; } // Remove groups that can't be accessed if ($permissions) { for ($i = $batchStartPos; $i < sizeOf($groups); $i++) { if (!$permissions->canAccess($groups[$i]->libraryID, 'view')) { array_splice($groups, $i, 1); $i--; $totalResults--; } } } $times++; if ($times == $maxTimes) { Z_Core::logError('Too many queries in Zotero_Groups::getAllAdvanced()'); break; } if (empty($params['limit'])) { break; } // If we have enough groups to fill the limit, stop if (sizeOf($groups) > $params['limit']) { break; } // If there no more rows, stop if ($start + sizeOf($rows) >= $foundRows) { break; } $start = $start + sizeOf($rows); // Get number we still need plus the buffer or all remaining, whichever is lower $limit = min($params['limit'] - sizeOf($groups) + $buffer, $foundRows - $start); } // TODO: generate previous start value if (!$groups) { return array('results' => array(), 'total' => 0); } // Fake limiting -- we can't just use SQL limit because // some groups might be inaccessible if (!empty($params['limit'])) { $groups = array_slice($groups, 0, $params['limit']); } $results = array('results' => $groups, 'total' => $totalResults); return $results; }