| Total Complexity | 71 |
| Total Lines | 302 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 1 |
Complex classes like UpdateUUID often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UpdateUUID, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 69 | class UpdateUUID extends Command { |
||
| 70 | /** @var UserMapping */ |
||
| 71 | private $userMapping; |
||
| 72 | /** @var GroupMapping */ |
||
| 73 | private $groupMapping; |
||
| 74 | /** @var User_Proxy */ |
||
| 75 | private $userProxy; |
||
| 76 | /** @var Group_Proxy */ |
||
| 77 | private $groupProxy; |
||
| 78 | /** @var array<UuidUpdateReport[]> */ |
||
| 79 | protected $reports = []; |
||
| 80 | /** @var LoggerInterface */ |
||
| 81 | private $logger; |
||
| 82 | /** @var bool */ |
||
| 83 | private $dryRun = false; |
||
| 84 | |||
| 85 | public function __construct(UserMapping $userMapping, GroupMapping $groupMapping, User_Proxy $userProxy, Group_Proxy $groupProxy, LoggerInterface $logger) { |
||
| 86 | $this->userMapping = $userMapping; |
||
| 87 | $this->groupMapping = $groupMapping; |
||
| 88 | $this->userProxy = $userProxy; |
||
| 89 | $this->groupProxy = $groupProxy; |
||
| 90 | $this->logger = $logger; |
||
| 91 | $this->reports = [ |
||
| 92 | UuidUpdateReport::UPDATED => [], |
||
| 93 | UuidUpdateReport::UNKNOWN => [], |
||
| 94 | UuidUpdateReport::UNREADABLE => [], |
||
| 95 | UuidUpdateReport::UNWRITABLE => [], |
||
| 96 | UuidUpdateReport::UNMAPPED => [], |
||
| 97 | ]; |
||
| 98 | parent::__construct(); |
||
| 99 | } |
||
| 100 | |||
| 101 | protected function configure(): void { |
||
| 134 | ) |
||
| 135 | ; |
||
| 136 | } |
||
| 137 | |||
| 138 | protected function execute(InputInterface $input, OutputInterface $output): int { |
||
| 139 | $this->dryRun = $input->getOption('dry-run'); |
||
| 140 | $entriesToUpdate = $this->estimateNumberOfUpdates($input); |
||
| 141 | $progress = new ProgressBar($output); |
||
| 142 | $progress->start($entriesToUpdate); |
||
| 143 | foreach($this->handleUpdates($input) as $_) { |
||
| 144 | $progress->advance(); |
||
| 145 | } |
||
| 146 | $progress->finish(); |
||
| 147 | $output->writeln(''); |
||
| 148 | $this->printReport($output); |
||
| 149 | return count($this->reports[UuidUpdateReport::UNMAPPED]) === 0 |
||
| 150 | && count($this->reports[UuidUpdateReport::UNREADABLE]) === 0 |
||
| 151 | && count($this->reports[UuidUpdateReport::UNWRITABLE]) === 0 |
||
| 152 | ? 0 |
||
| 153 | : 1; |
||
| 154 | } |
||
| 155 | |||
| 156 | protected function printReport(OutputInterface $output): void { |
||
| 157 | if ($output->isQuiet()) { |
||
| 158 | return; |
||
| 159 | } |
||
| 160 | |||
| 161 | if (count($this->reports[UuidUpdateReport::UPDATED]) === 0) { |
||
| 162 | $output->writeln('<info>No record was updated.</info>'); |
||
| 163 | } else { |
||
| 164 | $output->writeln(sprintf('<info>%d record(s) were updated.</info>', count($this->reports[UuidUpdateReport::UPDATED]))); |
||
| 165 | if ($output->isVerbose()) { |
||
| 166 | /** @var UuidUpdateReport $report */ |
||
| 167 | foreach ($this->reports[UuidUpdateReport::UPDATED] as $report) { |
||
| 168 | $output->writeln(sprintf(' %s had their old UUID %s updated to %s', $report->id, $report->oldUuid, $report->newUuid)); |
||
| 169 | } |
||
| 170 | $output->writeln(''); |
||
| 171 | } |
||
| 172 | } |
||
| 173 | |||
| 174 | if (count($this->reports[UuidUpdateReport::UNMAPPED]) > 0) { |
||
| 175 | $output->writeln(sprintf('<error>%d provided IDs were not mapped. These were:</error>', count($this->reports[UuidUpdateReport::UNMAPPED]))); |
||
| 176 | /** @var UuidUpdateReport $report */ |
||
| 177 | foreach ($this->reports[UuidUpdateReport::UNMAPPED] as $report) { |
||
| 178 | if (!empty($report->id)) { |
||
| 179 | $output->writeln(sprintf(' %s: %s', |
||
| 180 | $report->isUser ? 'User' : 'Group', $report->id)); |
||
| 181 | } else if (!empty($report->dn)) { |
||
| 182 | $output->writeln(sprintf(' DN: %s', $report->dn)); |
||
| 183 | } |
||
| 184 | } |
||
| 185 | $output->writeln(''); |
||
| 186 | } |
||
| 187 | |||
| 188 | if (count($this->reports[UuidUpdateReport::UNKNOWN]) > 0) { |
||
| 189 | $output->writeln(sprintf('<info>%d provided IDs were unknown on LDAP.</info>', count($this->reports[UuidUpdateReport::UNKNOWN]))); |
||
| 190 | if ($output->isVerbose()) { |
||
| 191 | /** @var UuidUpdateReport $report */ |
||
| 192 | foreach ($this->reports[UuidUpdateReport::UNKNOWN] as $report) { |
||
| 193 | $output->writeln(sprintf(' %s: %s',$report->isUser ? 'User' : 'Group', $report->id)); |
||
| 194 | } |
||
| 195 | $output->writeln(PHP_EOL . 'Old users can be removed along with their data per occ user:delete.' . PHP_EOL); |
||
| 196 | } |
||
| 197 | } |
||
| 198 | |||
| 199 | if (count($this->reports[UuidUpdateReport::UNREADABLE]) > 0) { |
||
| 200 | $output->writeln(sprintf('<error>For %d records, the UUID could not be read. Double-check your configuration.</error>', count($this->reports[UuidUpdateReport::UNREADABLE]))); |
||
| 201 | if ($output->isVerbose()) { |
||
| 202 | /** @var UuidUpdateReport $report */ |
||
| 203 | foreach ($this->reports[UuidUpdateReport::UNREADABLE] as $report) { |
||
| 204 | $output->writeln(sprintf(' %s: %s',$report->isUser ? 'User' : 'Group', $report->id)); |
||
| 205 | } |
||
| 206 | } |
||
| 207 | } |
||
| 208 | |||
| 209 | if (count($this->reports[UuidUpdateReport::UNWRITABLE]) > 0) { |
||
| 210 | $output->writeln(sprintf('<error>For %d records, the UUID could not be saved to database. Double-check your configuration.</error>', count($this->reports[UuidUpdateReport::UNWRITABLE]))); |
||
| 211 | if ($output->isVerbose()) { |
||
| 212 | /** @var UuidUpdateReport $report */ |
||
| 213 | foreach ($this->reports[UuidUpdateReport::UNWRITABLE] as $report) { |
||
| 214 | $output->writeln(sprintf(' %s: %s',$report->isUser ? 'User' : 'Group', $report->id)); |
||
| 215 | } |
||
| 216 | } |
||
| 217 | } |
||
| 218 | } |
||
| 219 | |||
| 220 | protected function handleUpdates(InputInterface $input): \Generator { |
||
| 221 | if ($input->getOption('all')) { |
||
| 222 | foreach($this->handleMappingBasedUpdates(false) as $_) { |
||
| 223 | yield; |
||
| 224 | } |
||
| 225 | } else if ($input->getOption('userId') |
||
| 226 | || $input->getOption('groupId') |
||
| 227 | || $input->getOption('dn') |
||
| 228 | ) { |
||
| 229 | foreach($this->handleUpdatesByUserId($input->getOption('userId')) as $_) { |
||
| 230 | yield; |
||
| 231 | } |
||
| 232 | foreach($this->handleUpdatesByGroupId($input->getOption('groupId')) as $_) { |
||
| 233 | yield; |
||
| 234 | } |
||
| 235 | foreach($this->handleUpdatesByDN($input->getOption('dn')) as $_) { |
||
| 236 | yield; |
||
| 237 | } |
||
| 238 | } else { |
||
| 239 | foreach($this->handleMappingBasedUpdates(true) as $_) { |
||
| 240 | yield; |
||
| 241 | } |
||
| 242 | } |
||
| 243 | } |
||
| 244 | |||
| 245 | protected function handleUpdatesByUserId(array $userIds): \Generator { |
||
| 246 | foreach($this->handleUpdatesByEntryId($userIds, $this->userMapping) as $_) { |
||
| 247 | yield; |
||
| 248 | } |
||
| 249 | } |
||
| 250 | |||
| 251 | protected function handleUpdatesByGroupId(array $groupIds): \Generator { |
||
| 252 | foreach($this->handleUpdatesByEntryId($groupIds, $this->groupMapping) as $_) { |
||
| 253 | yield; |
||
| 254 | } |
||
| 255 | } |
||
| 256 | |||
| 257 | protected function handleUpdatesByDN(array $dns): \Generator { |
||
| 258 | $userList = $groupList = []; |
||
| 259 | while ($dn = array_pop($dns)) { |
||
| 260 | $uuid = $this->userMapping->getUUIDByDN($dn); |
||
| 261 | if ($uuid) { |
||
| 262 | $id = $this->userMapping->getNameByDN($dn); |
||
| 263 | $userList[] = ['name' => $id, 'uuid' => $uuid]; |
||
| 264 | continue; |
||
| 265 | } |
||
| 266 | $uuid = $this->groupMapping->getUUIDByDN($dn); |
||
| 267 | if ($uuid) { |
||
| 268 | $id = $this->groupMapping->getNameByDN($dn); |
||
| 269 | $groupList[] = ['name' => $id, 'uuid' => $uuid]; |
||
| 270 | continue; |
||
| 271 | } |
||
| 272 | $this->reports[UuidUpdateReport::UNMAPPED][] = new UuidUpdateReport('', $dn, true, UuidUpdateReport::UNMAPPED); |
||
| 273 | yield; |
||
| 274 | } |
||
| 275 | foreach($this->handleUpdatesByList($this->userMapping, $userList) as $_) { |
||
| 276 | yield; |
||
| 277 | } |
||
| 278 | foreach($this->handleUpdatesByList($this->groupMapping, $groupList) as $_) { |
||
| 279 | yield; |
||
| 280 | } |
||
| 281 | } |
||
| 282 | |||
| 283 | protected function handleUpdatesByEntryId(array $ids, AbstractMapping $mapping): \Generator { |
||
| 284 | $isUser = $mapping instanceof UserMapping; |
||
| 285 | $list = []; |
||
| 286 | while ($id = array_pop($ids)) { |
||
| 287 | if(!$dn = $mapping->getDNByName($id)) { |
||
| 288 | $this->reports[UuidUpdateReport::UNMAPPED][] = new UuidUpdateReport($id, '', $isUser, UuidUpdateReport::UNMAPPED); |
||
| 289 | yield; |
||
| 290 | continue; |
||
| 291 | } |
||
| 292 | // Since we know it was mapped the UUID is populated |
||
| 293 | $uuid = $mapping->getUUIDByDN($dn); |
||
| 294 | $list[] = ['name' => $id, 'uuid' => $uuid]; |
||
| 295 | } |
||
| 296 | foreach($this->handleUpdatesByList($mapping, $list) as $_) { |
||
| 297 | yield; |
||
| 298 | } |
||
| 299 | } |
||
| 300 | |||
| 301 | protected function handleMappingBasedUpdates(bool $invalidatedOnly): \Generator { |
||
| 302 | $limit = 1000; |
||
| 303 | /** @var AbstractMapping $mapping*/ |
||
| 304 | foreach([$this->userMapping, $this->groupMapping] as $mapping) { |
||
| 305 | $offset = 0; |
||
| 306 | do { |
||
| 307 | $list = $mapping->getList($offset, $limit, $invalidatedOnly); |
||
| 308 | $offset += $limit; |
||
| 309 | |||
| 310 | foreach($this->handleUpdatesByList($mapping, $list) as $tick) { |
||
| 311 | yield; // null, for it only advances progress counter |
||
| 312 | } |
||
| 313 | } while (count($list) === $limit); |
||
| 314 | } |
||
| 315 | } |
||
| 316 | |||
| 317 | protected function handleUpdatesByList(AbstractMapping $mapping, array $list): \Generator { |
||
| 356 | } |
||
| 357 | } |
||
| 358 | |||
| 359 | protected function estimateNumberOfUpdates(InputInterface $input): int { |
||
| 360 | if ($input->getOption('all')) { |
||
| 361 | return $this->userMapping->count() + $this->groupMapping->count(); |
||
| 371 | } |
||
| 372 | } |
||
| 373 | |||
| 374 | } |
||
| 375 |