‪TYPO3CMS  11.5
GroupResolver.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
25 
36 {
37  protected EventDispatcherInterface ‪$eventDispatcher;
38  protected string ‪$sourceTable = '';
39  protected string ‪$sourceField = 'usergroup';
40  protected string ‪$recursiveSourceField = 'subgroup';
41 
42  public function ‪__construct(EventDispatcherInterface ‪$eventDispatcher)
43  {
44  $this->eventDispatcher = ‪$eventDispatcher;
45  }
46 
58  public function ‪resolveGroupsForUser(array $userRecord, string ‪$sourceTable): array
59  {
60  $this->sourceTable = ‪$sourceTable;
61  $originalGroupIds = ‪GeneralUtility::intExplode(',', $userRecord[$this->sourceField] ?? '', true);
62  $resolvedGroups = $this->‪fetchGroupsRecursive($originalGroupIds);
63  $event = $this->eventDispatcher->dispatch(new ‪AfterGroupsResolvedEvent(‪$sourceTable, $resolvedGroups, $originalGroupIds, $userRecord));
64  return $event->getGroups();
65  }
66 
74  protected function ‪fetchGroupsRecursive(array $groupIds, array $processedGroupIds = []): array
75  {
76  if (empty($groupIds)) {
77  return [];
78  }
79  $foundGroups = $this->‪fetchRowsFromDatabase($groupIds);
80  $validGroups = [];
81  foreach ($groupIds as $groupId) {
82  // Database did not find the record
83  if (!is_array($foundGroups[$groupId] ?? null)) {
84  continue;
85  }
86  // Record was already processed, continue to avoid adding this group again
87  if (in_array($groupId, $processedGroupIds, true)) {
88  continue;
89  }
90  // Add sub groups first
91  $subgroupIds = ‪GeneralUtility::intExplode(',', $foundGroups[$groupId][$this->recursiveSourceField] ?? '', true);
92  if (!empty($subgroupIds)) {
93  $subgroups = $this->‪fetchGroupsRecursive($subgroupIds, array_merge($processedGroupIds, [$groupId]));
94  $validGroups = array_merge($validGroups, $subgroups);
95  }
96  // Add main group after sub groups have been added
97  $validGroups[] = $foundGroups[$groupId];
98  }
99  return $validGroups;
100  }
101 
108  protected function ‪fetchRowsFromDatabase(array $groupIds): array
109  {
110  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->sourceTable);
111  $result = $queryBuilder
112  ->select('*')
113  ->from($this->sourceTable)
114  ->where(
115  $queryBuilder->expr()->in(
116  'uid',
117  $queryBuilder->createNamedParameter(
118  $groupIds,
119  Connection::PARAM_INT_ARRAY
120  )
121  )
122  )
123  ->executeQuery();
124  $groups = [];
125  while ($row = $result->fetchAssociative()) {
126  $groups[(int)$row['uid']] = $row;
127  }
128  return $groups;
129  }
130 
141  public function ‪findAllUsersInGroups(array $groupIds, string ‪$sourceTable, string $userSourceTable): array
142  {
143  $this->sourceTable = ‪$sourceTable;
144 
145  // Ensure the given groups exist
146  $mainGroups = $this->‪fetchRowsFromDatabase($groupIds);
147  $groupIds = array_map('intval', array_column($mainGroups, 'uid'));
148  if (empty($groupIds)) {
149  return [];
150  }
151  $parentGroupIds = $this->‪fetchParentGroupsRecursive($groupIds, $groupIds);
152  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userSourceTable);
153  $queryBuilder
154  ->select('*')
155  ->from($userSourceTable);
156 
157  $constraints = [];
158  foreach ($groupIds as $groupUid) {
159  $constraints[] = $queryBuilder->expr()->inSet($this->sourceField, (string)$groupUid);
160  }
161  foreach ($parentGroupIds as $groupUid) {
162  $constraints[] = $queryBuilder->expr()->inSet($this->sourceField, (string)$groupUid);
163  }
164 
165  $users = $queryBuilder
166  ->where(
167  $queryBuilder->expr()->orX(...$constraints)
168  )
169  ->executeQuery()
170  ->fetchAllAssociative();
171  return !empty($users) ? $users : [];
172  }
173 
181  protected function ‪fetchParentGroupsRecursive(array $groupIds, array $processedGroupIds = []): array
182  {
183  if (empty($groupIds)) {
184  return [];
185  }
186  $parentGroups = $this->‪fetchParentGroupsFromDatabase($groupIds);
187  $validParentGroupIds = [];
188  foreach ($parentGroups as $parentGroup) {
189  $parentGroupId = (int)$parentGroup['uid'];
190  // Record was already processed, continue to avoid adding this group again
191  if (in_array($parentGroupId, $processedGroupIds, true)) {
192  continue;
193  }
194  $processedGroupIds[] = $parentGroupId;
195  $validParentGroupIds[] = $parentGroupId;
196  }
197 
198  $grandParentGroups = $this->‪fetchParentGroupsRecursive($validParentGroupIds, $processedGroupIds);
199  return array_merge($validParentGroupIds, $grandParentGroups);
200  }
201 
209  protected function ‪fetchParentGroupsFromDatabase(array $subgroupIds): array
210  {
211  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->sourceTable);
212  $queryBuilder
213  ->select('*')
214  ->from($this->sourceTable);
215 
216  $constraints = [];
217  foreach ($subgroupIds as $subgroupId) {
218  $constraints[] = $queryBuilder->expr()->inSet($this->recursiveSourceField, (string)$subgroupId);
219  }
220 
221  $result = $queryBuilder
222  ->where(
223  $queryBuilder->expr()->orX(...$constraints)
224  )
225  ->executeQuery();
226 
227  $groups = [];
228  while ($row = $result->fetchAssociative()) {
229  $groups[(int)$row['uid']] = $row;
230  }
231  return $groups;
232  }
233 }
‪TYPO3\CMS\Core\Authentication\GroupResolver\$sourceTable
‪string $sourceTable
Definition: GroupResolver.php:38
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchGroupsRecursive
‪array fetchGroupsRecursive(array $groupIds, array $processedGroupIds=[])
Definition: GroupResolver.php:74
‪TYPO3\CMS\Core\Authentication
Definition: AbstractAuthenticationService.php:16
‪TYPO3\CMS\Core\Authentication\GroupResolver\$recursiveSourceField
‪string $recursiveSourceField
Definition: GroupResolver.php:40
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchParentGroupsRecursive
‪array fetchParentGroupsRecursive(array $groupIds, array $processedGroupIds=[])
Definition: GroupResolver.php:181
‪TYPO3\CMS\Core\Authentication\GroupResolver\findAllUsersInGroups
‪array findAllUsersInGroups(array $groupIds, string $sourceTable, string $userSourceTable)
Definition: GroupResolver.php:141
‪TYPO3\CMS\Core\Authentication\Event\AfterGroupsResolvedEvent
Definition: AfterGroupsResolvedEvent.php:24
‪TYPO3\CMS\Core\Authentication\GroupResolver\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: GroupResolver.php:37
‪TYPO3\CMS\Core\Authentication\GroupResolver\$sourceField
‪string $sourceField
Definition: GroupResolver.php:39
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchRowsFromDatabase
‪array fetchRowsFromDatabase(array $groupIds)
Definition: GroupResolver.php:108
‪TYPO3\CMS\Core\Authentication\GroupResolver\__construct
‪__construct(EventDispatcherInterface $eventDispatcher)
Definition: GroupResolver.php:42
‪TYPO3\CMS\Core\Authentication\GroupResolver
Definition: GroupResolver.php:36
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Authentication\GroupResolver\resolveGroupsForUser
‪array resolveGroupsForUser(array $userRecord, string $sourceTable)
Definition: GroupResolver.php:58
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:927
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchParentGroupsFromDatabase
‪array fetchParentGroupsFromDatabase(array $subgroupIds)
Definition: GroupResolver.php:209