‪TYPO3CMS  ‪main
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(',', (string)($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 
72  protected function ‪fetchGroupsRecursive(array $groupIds, array $processedGroupIds = []): array
73  {
74  if (empty($groupIds)) {
75  return [];
76  }
77  $foundGroups = $this->‪fetchRowsFromDatabase($groupIds);
78  $validGroups = [];
79  foreach ($groupIds as $groupId) {
80  // Database did not find the record
81  if (!is_array($foundGroups[$groupId] ?? null)) {
82  continue;
83  }
84  // Record was already processed, continue to avoid adding this group again
85  if (in_array($groupId, $processedGroupIds, true)) {
86  continue;
87  }
88  // Add sub groups first
89  $subgroupIds = ‪GeneralUtility::intExplode(',', (string)($foundGroups[$groupId][$this->recursiveSourceField] ?? ''), true);
90  if (!empty($subgroupIds)) {
91  $subgroups = $this->‪fetchGroupsRecursive($subgroupIds, array_merge($processedGroupIds, [$groupId]));
92  $validGroups = array_merge($validGroups, $subgroups);
93  }
94  // Add main group after sub groups have been added
95  $validGroups[] = $foundGroups[$groupId];
96  }
97  return $validGroups;
98  }
99 
105  protected function ‪fetchRowsFromDatabase(array $groupIds): array
106  {
107  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->sourceTable);
108  $result = $queryBuilder
109  ->select('*')
110  ->from($this->sourceTable)
111  ->where(
112  $queryBuilder->expr()->in(
113  'uid',
114  $queryBuilder->createNamedParameter(
115  $groupIds,
117  )
118  )
119  )
120  ->executeQuery();
121  $groups = [];
122  while ($row = $result->fetchAssociative()) {
123  $groups[(int)$row['uid']] = $row;
124  }
125  return $groups;
126  }
127 
138  public function ‪findAllUsersInGroups(array $groupIds, string ‪$sourceTable, string $userSourceTable): array
139  {
140  $this->sourceTable = ‪$sourceTable;
141 
142  // Ensure the given groups exist
143  $mainGroups = $this->‪fetchRowsFromDatabase($groupIds);
144  $groupIds = array_map(intval(...), array_column($mainGroups, 'uid'));
145  if (empty($groupIds)) {
146  return [];
147  }
148  $parentGroupIds = $this->‪fetchParentGroupsRecursive($groupIds, $groupIds);
149  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userSourceTable);
150  $queryBuilder
151  ->select('*')
152  ->from($userSourceTable);
153 
154  $constraints = [];
155  foreach ($groupIds as $groupUid) {
156  $constraints[] = $queryBuilder->expr()->inSet($this->sourceField, (string)$groupUid);
157  }
158  foreach ($parentGroupIds as $groupUid) {
159  $constraints[] = $queryBuilder->expr()->inSet($this->sourceField, (string)$groupUid);
160  }
161 
162  $users = $queryBuilder
163  ->where(
164  $queryBuilder->expr()->or(...$constraints)
165  )
166  ->executeQuery()
167  ->fetchAllAssociative();
168  return !empty($users) ? $users : [];
169  }
170 
178  protected function ‪fetchParentGroupsRecursive(array $groupIds, array $processedGroupIds = []): array
179  {
180  if (empty($groupIds)) {
181  return [];
182  }
183  $parentGroups = $this->‪fetchParentGroupsFromDatabase($groupIds);
184  $validParentGroupIds = [];
185  foreach ($parentGroups as $parentGroup) {
186  $parentGroupId = (int)$parentGroup['uid'];
187  // Record was already processed, continue to avoid adding this group again
188  if (in_array($parentGroupId, $processedGroupIds, true)) {
189  continue;
190  }
191  $processedGroupIds[] = $parentGroupId;
192  $validParentGroupIds[] = $parentGroupId;
193  }
194 
195  $grandParentGroups = $this->‪fetchParentGroupsRecursive($validParentGroupIds, $processedGroupIds);
196  return array_merge($validParentGroupIds, $grandParentGroups);
197  }
198 
203  protected function ‪fetchParentGroupsFromDatabase(array $subgroupIds): array
204  {
205  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->sourceTable);
206  $queryBuilder
207  ->select('*')
208  ->from($this->sourceTable);
209 
210  $constraints = [];
211  foreach ($subgroupIds as $subgroupId) {
212  $constraints[] = $queryBuilder->expr()->inSet($this->recursiveSourceField, (string)$subgroupId);
213  }
214 
215  $result = $queryBuilder
216  ->where(
217  $queryBuilder->expr()->or(...$constraints)
218  )
219  ->executeQuery();
220 
221  $groups = [];
222  while ($row = $result->fetchAssociative()) {
223  $groups[(int)$row['uid']] = $row;
224  }
225  return $groups;
226  }
227 }
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchParentGroupsFromDatabase
‪fetchParentGroupsFromDatabase(array $subgroupIds)
Definition: GroupResolver.php:203
‪TYPO3\CMS\Core\Authentication\GroupResolver\$sourceTable
‪string $sourceTable
Definition: GroupResolver.php:38
‪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:178
‪TYPO3\CMS\Core\Authentication\GroupResolver\findAllUsersInGroups
‪array findAllUsersInGroups(array $groupIds, string $sourceTable, string $userSourceTable)
Definition: GroupResolver.php:138
‪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:105
‪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:41
‪TYPO3\CMS\Core\Authentication\GroupResolver\resolveGroupsForUser
‪array resolveGroupsForUser(array $userRecord, string $sourceTable)
Definition: GroupResolver.php:58
‪TYPO3\CMS\Core\Authentication\GroupResolver\fetchGroupsRecursive
‪fetchGroupsRecursive(array $groupIds, array $processedGroupIds=[])
Definition: GroupResolver.php:72
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT_ARRAY
‪const PARAM_INT_ARRAY
Definition: Connection.php:72