aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Group
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Group')
-rw-r--r--lib/private/Group/Database.php85
-rw-r--r--lib/private/Group/Manager.php65
2 files changed, 135 insertions, 15 deletions
diff --git a/lib/private/Group/Database.php b/lib/private/Group/Database.php
index ef5641d8137..0fcc151363b 100644
--- a/lib/private/Group/Database.php
+++ b/lib/private/Group/Database.php
@@ -62,11 +62,9 @@ class Database extends ABackend implements
ISetDisplayNameBackend,
ISearchableGroupBackend,
INamedBackend {
- /** @var string[] */
+ /** @var array<string, array{gid: string, displayname: string}> */
private $groupCache = [];
-
- /** @var IDBConnection */
- private $dbConn;
+ private ?IDBConnection $dbConn;
/**
* \OC\Group\Database constructor.
@@ -270,7 +268,7 @@ class Database extends ABackend implements
$this->fixDI();
$query = $this->dbConn->getQueryBuilder();
- $query->select('gid')
+ $query->select('gid', 'displayname')
->from('groups')
->orderBy('gid', 'ASC');
@@ -293,6 +291,10 @@ class Database extends ABackend implements
$groups = [];
while ($row = $result->fetch()) {
+ $this->groupCache[$row['gid']] = [
+ 'displayname' => $row['displayname'],
+ 'gid' => $row['gid'],
+ ];
$groups[] = $row['gid'];
}
$result->closeCursor();
@@ -332,6 +334,42 @@ class Database extends ABackend implements
}
/**
+ * {@inheritdoc}
+ */
+ public function groupsExists(array $gids): array {
+ $notFoundGids = [];
+ $existingGroups = [];
+
+ // In case the data is already locally accessible, not need to do SQL query
+ // or do a SQL query but with a smaller in clause
+ foreach ($gids as $gid) {
+ if (isset($this->groupCache[$gid])) {
+ $existingGroups[] = $gid;
+ } else {
+ $notFoundGids[] = $gid;
+ }
+ }
+
+ foreach (array_chunk($notFoundGids, 1000) as $chunk) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $result = $qb->select('gid', 'displayname')
+ ->from('groups')
+ ->where($qb->expr()->in('gid', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY)))
+ ->executeQuery();
+ while ($row = $result->fetch()) {
+ $this->groupCache[$row['gid']] = [
+ 'displayname' => $row['displayname'],
+ 'gid' => $row['gid'],
+ ];
+ $existingGroups[] = $gid;
+ }
+ $result->closeCursor();
+ }
+
+ return $existingGroups;
+ }
+
+ /**
* Get a list of all users in a group
* @param string $gid
* @param string $search
@@ -488,6 +526,43 @@ class Database extends ABackend implements
return [];
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getGroupsDetails(array $gids): array {
+ $notFoundGids = [];
+ $details = [];
+
+ // In case the data is already locally accessible, not need to do SQL query
+ // or do a SQL query but with a smaller in clause
+ foreach ($gids as $gid) {
+ if (isset($this->groupCache[$gid])) {
+ $details[$gid] = ['displayName' => $this->groupCache[$gid]['displayname']];
+ } else {
+ $notFoundGids[] = $gid;
+ }
+ }
+
+ foreach (array_chunk($notFoundGids, 1000) as $chunk) {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('gid', 'displayname')
+ ->from('groups')
+ ->where($query->expr()->in('gid', $query->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY)));
+
+ $result = $query->executeQuery();
+ while ($row = $result->fetch()) {
+ $details[$row['gid']] = ['displayName' => $row['displayname']];
+ $this->groupCache[$row['gid']] = [
+ 'displayname' => $row['displayname'],
+ 'gid' => $row['gid'],
+ ];
+ }
+ $result->closeCursor();
+ }
+
+ return $details;
+ }
+
public function setDisplayName(string $gid, string $displayName): bool {
if (!$this->groupExists($gid)) {
return false;
diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php
index c43b5165a79..924b9a3b6a6 100644
--- a/lib/private/Group/Manager.php
+++ b/lib/private/Group/Manager.php
@@ -21,6 +21,7 @@
* @author Vincent Petry <vincent@nextcloud.com>
* @author Vinicius Cubas Brand <vinicius@eita.org.br>
* @author voxsim "Simon Vocella"
+ * @author Carl Schwan <carl@carlschwan.eu>
*
* @license AGPL-3.0
*
@@ -41,6 +42,7 @@ namespace OC\Group;
use OC\Hooks\PublicEmitter;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Group\Backend\IGroupDetailsBackend;
use OCP\Group\Events\BeforeGroupCreatedEvent;
use OCP\Group\Events\GroupCreatedEvent;
use OCP\GroupInterface;
@@ -74,10 +76,10 @@ class Manager extends PublicEmitter implements IGroupManager {
private IEventDispatcher $dispatcher;
private LoggerInterface $logger;
- /** @var \OC\Group\Group[] */
+ /** @var array<string, IGroup> */
private $cachedGroups = [];
- /** @var (string[])[] */
+ /** @var array<string, list<string>> */
private $cachedUserGroups = [];
/** @var \OC\SubAdmin */
@@ -185,7 +187,7 @@ class Manager extends PublicEmitter implements IGroupManager {
if ($backend->implementsActions(Backend::GROUP_DETAILS)) {
$groupData = $backend->getGroupDetails($gid);
if (is_array($groupData) && !empty($groupData)) {
- // take the display name from the first backend that has a non-null one
+ // take the display name from the last backend that has a non-null one
if (is_null($displayName) && isset($groupData['displayName'])) {
$displayName = $groupData['displayName'];
}
@@ -198,11 +200,58 @@ class Manager extends PublicEmitter implements IGroupManager {
if (count($backends) === 0) {
return null;
}
+ /** @var GroupInterface[] $backends */
$this->cachedGroups[$gid] = new Group($gid, $backends, $this->dispatcher, $this->userManager, $this, $displayName);
return $this->cachedGroups[$gid];
}
/**
+ * @brief Batch method to create group objects
+ *
+ * @param list<string> $gids List of groupIds for which we want to create a IGroup object
+ * @param array<string, string> $displayNames Array containing already know display name for a groupId
+ * @return array<string, IGroup>
+ */
+ protected function getGroupsObject(array $gids, array $displayNames = []): array {
+ $backends = [];
+ $groups = [];
+ foreach ($gids as $gid) {
+ $backends[$gid] = [];
+ if (!isset($displayNames[$gid])) {
+ $displayNames[$gid] = null;
+ }
+ }
+ foreach ($this->backends as $backend) {
+ if ($backend instanceof IGroupDetailsBackend || $backend->implementsActions(GroupInterface::GROUP_DETAILS)) {
+ /** @var IGroupDetailsBackend $backend */
+ $groupDatas = $backend->getGroupsDetails($gids);
+ foreach ($groupDatas as $gid => $groupData) {
+ if (!empty($groupData)) {
+ // take the display name from the last backend that has a non-null one
+ if (isset($groupData['displayName'])) {
+ $displayNames[$gid] = $groupData['displayName'];
+ }
+ $backends[$gid][] = $backend;
+ }
+ }
+ } else {
+ $existingGroups = $backend->groupsExists($gids);
+ foreach ($existingGroups as $group) {
+ $backends[$group][] = $backend;
+ }
+ }
+ }
+ foreach ($gids as $gid) {
+ if (count($backends[$gid]) === 0) {
+ continue;
+ }
+ $this->cachedGroups[$gid] = new Group($gid, $backends[$gid], $this->dispatcher, $this->userManager, $this, $displayNames[$gid]);
+ $groups[$gid] = $this->cachedGroups[$gid];
+ }
+ return $groups;
+ }
+
+ /**
* @param string $gid
* @return bool
*/
@@ -246,13 +295,9 @@ class Manager extends PublicEmitter implements IGroupManager {
$groups = [];
foreach ($this->backends as $backend) {
$groupIds = $backend->getGroups($search, $limit ?? -1, $offset ?? 0);
- foreach ($groupIds as $groupId) {
- $aGroup = $this->get($groupId);
- if ($aGroup instanceof IGroup) {
- $groups[$groupId] = $aGroup;
- } else {
- $this->logger->debug('Group "' . $groupId . '" was returned by search but not found through direct access', ['app' => 'core']);
- }
+ $newGroups = $this->getGroupsObject($groupIds);
+ foreach ($newGroups as $groupId => $group) {
+ $groups[$groupId] = $group;
}
if (!is_null($limit) and $limit <= 0) {
return array_values($groups);