ApiService.php
11 months ago
ElementService.php
11 months ago
EmailService.php
11 months ago
FormService.php
11 months ago
LevelOrderService.php
11 months ago
LevelService.php
11 months ago
MembershipService.php
11 months ago
RedirectService.php
11 months ago
SanitizationService.php
11 months ago
StatisticsService.php
11 months ago
UserService.php
11 months ago
LevelOrderService.php
212 lines
| 1 | <?php declare(strict_types=1); |
| 2 | |
| 3 | namespace FapiMember\Service; |
| 4 | |
| 5 | use FapiMember\Container\Container; |
| 6 | use FapiMember\Model\MemberSection; |
| 7 | use FapiMember\Repository\LevelOrderRepository; |
| 8 | use FapiMember\Repository\LevelRepository; |
| 9 | |
| 10 | class LevelOrderService |
| 11 | { |
| 12 | private LevelRepository $levelRepository; |
| 13 | private LevelOrderRepository $levelOrderRepository; |
| 14 | |
| 15 | public function __construct() |
| 16 | { |
| 17 | $this->levelRepository = Container::get(LevelRepository::class); |
| 18 | $this->levelOrderRepository = Container::get(LevelOrderRepository::class); |
| 19 | } |
| 20 | |
| 21 | public function reorder(int $reorderedLevelId, int $direction): bool |
| 22 | { |
| 23 | if ($direction !== 1 && $direction !== -1) { |
| 24 | return false; |
| 25 | } |
| 26 | |
| 27 | $ordering = $this->getOrder(); |
| 28 | $reorderedSectionIndex = null; |
| 29 | $reorderedLevelIndex = null; |
| 30 | $reordered = false; |
| 31 | |
| 32 | if (isset($ordering[$reorderedLevelId])) { |
| 33 | $reorderedSectionIndex = $ordering[$reorderedLevelId]['index']; |
| 34 | } |
| 35 | |
| 36 | foreach ($ordering as $orderSectionId => $orderSection) { |
| 37 | if ($reorderedSectionIndex !== null) { |
| 38 | if ($orderSection['index'] === $reorderedSectionIndex + $direction) { |
| 39 | $ordering[$reorderedLevelId]['index'] = $orderSection['index']; |
| 40 | $ordering[$orderSectionId]['index'] = $reorderedSectionIndex; |
| 41 | $reordered = true; |
| 42 | } |
| 43 | } else { |
| 44 | $orderLevels = $orderSection['levels']; |
| 45 | if (isset($orderLevels[$reorderedLevelId])) { |
| 46 | $reorderedLevelIndex = $orderLevels[$reorderedLevelId]; |
| 47 | } |
| 48 | |
| 49 | if ($reorderedLevelIndex !== null) { |
| 50 | foreach ($orderLevels as $orderLevelId => $orderLevel) { |
| 51 | if ($orderLevel === $reorderedLevelIndex + $direction) { |
| 52 | $ordering[$orderSectionId]['levels'][$reorderedLevelId] = $orderLevel; |
| 53 | $ordering[$orderSectionId]['levels'][$orderLevelId] = $reorderedLevelIndex; |
| 54 | $reordered = true; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | break; |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | $this->levelOrderRepository->set($ordering); |
| 64 | |
| 65 | return $reordered; |
| 66 | } |
| 67 | |
| 68 | public function getOrder(): array |
| 69 | { |
| 70 | $this->initializeOrder(); |
| 71 | return $this->levelOrderRepository->get(); |
| 72 | } |
| 73 | |
| 74 | public function initializeOrder(): void |
| 75 | { |
| 76 | $sections = $this->levelRepository->getAllSections(); |
| 77 | $ordering = $this->levelOrderRepository->get(); |
| 78 | |
| 79 | if (empty($ordering)) { |
| 80 | $ordering = $this->createOrder($sections); |
| 81 | } else { |
| 82 | $ordering = $this->fixOrder($ordering, $sections); |
| 83 | } |
| 84 | |
| 85 | $this->levelOrderRepository->set($ordering); |
| 86 | } |
| 87 | |
| 88 | /** @param array<MemberSection> $sections */ |
| 89 | private function createOrder(array $sections): array |
| 90 | { |
| 91 | $ordering = []; |
| 92 | |
| 93 | foreach ($sections as $sectionIndex => $section) { |
| 94 | $ordering[$section->getId()] = [ |
| 95 | 'index' => $sectionIndex, |
| 96 | 'levels' => [], |
| 97 | ]; |
| 98 | |
| 99 | $levels = $section->getLevels(); |
| 100 | |
| 101 | foreach ($levels as $levelIndex => $level) { |
| 102 | $ordering[$section->getId()]['levels'][$level->getId()] = $levelIndex; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | return $ordering; |
| 107 | } |
| 108 | |
| 109 | /** @param array<MemberSection> $sections */ |
| 110 | private function fixOrder(array $ordering, array $sections): array |
| 111 | { |
| 112 | $ordering = $this->removeNonExistentOrderItems($ordering, $sections); |
| 113 | $ordering = $this->shiftOrderIndexes($ordering); |
| 114 | $ordering = $this->addMissingOrderItems($ordering, $sections); |
| 115 | |
| 116 | return $ordering; |
| 117 | } |
| 118 | |
| 119 | /** @param array<MemberSection> $sections */ |
| 120 | private function removeNonExistentOrderItems(array $ordering, array $sections): array |
| 121 | { |
| 122 | $newOrdering = []; |
| 123 | |
| 124 | foreach ($sections as $section) { |
| 125 | $levelsOrder = []; |
| 126 | |
| 127 | foreach ($section->getLevels() as $level) { |
| 128 | if (isset( |
| 129 | $ordering[$section->getId()]['levels'][$level->getId()] |
| 130 | )) { |
| 131 | $levelsOrder[$level->getId()] = $ordering[$section->getId()]['levels'][$level->getId()]; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | if (isset($ordering[$section->getId()])) { |
| 136 | $newOrdering[$section->getId()] = ['levels' => $levelsOrder, 'index' => $ordering[$section->getId()]['index']]; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | return $newOrdering; |
| 141 | } |
| 142 | |
| 143 | private function shiftOrderIndexes(array $ordering): array |
| 144 | { |
| 145 | $sectionIndexes = array_column($ordering, 'index'); |
| 146 | sort($sectionIndexes); |
| 147 | |
| 148 | $sectionIndexMap = array_flip($sectionIndexes); |
| 149 | $newOrdering = []; |
| 150 | |
| 151 | foreach ($ordering as $sectionId => $sectionData) { |
| 152 | $newSectionIndex = $sectionIndexMap[$sectionData['index']]; |
| 153 | |
| 154 | $levelIndexes = array_values($sectionData['levels']); |
| 155 | sort($levelIndexes); |
| 156 | |
| 157 | $levelIndexMap = array_flip($levelIndexes); |
| 158 | $newLevels = []; |
| 159 | foreach ($sectionData['levels'] as $levelId => $levelIndex) { |
| 160 | $newLevels[$levelId] = $levelIndexMap[$levelIndex]; |
| 161 | } |
| 162 | |
| 163 | $newOrdering[$sectionId] = [ |
| 164 | 'index' => $newSectionIndex, |
| 165 | 'levels' => $newLevels, |
| 166 | ]; |
| 167 | } |
| 168 | |
| 169 | return $newOrdering; |
| 170 | } |
| 171 | |
| 172 | /** @param array<MemberSection> $sections */ |
| 173 | private function addMissingOrderItems(array $ordering, array $sections): array |
| 174 | { |
| 175 | $existingSectionIds = array_keys($ordering); |
| 176 | $existingLevelIds = []; |
| 177 | $nextSectionIndex = count($ordering); |
| 178 | $nextLevelIndexes = []; |
| 179 | |
| 180 | foreach ($ordering as $sectionId => $sectionData) { |
| 181 | $existingLevelIds = array_merge($existingLevelIds, array_keys($sectionData['levels'])); |
| 182 | $nextLevelIndexes[$sectionId] = count($sectionData['levels']); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | foreach ($sections as $section) { |
| 187 | $sectionId = $section->getId(); |
| 188 | if (!in_array($sectionId, $existingSectionIds, true)) { |
| 189 | // New section |
| 190 | $ordering[$sectionId] = [ |
| 191 | 'index' => $nextSectionIndex++, |
| 192 | 'levels' => [], |
| 193 | ]; |
| 194 | $nextLevelIndexes[$sectionId] = 0; |
| 195 | } |
| 196 | |
| 197 | foreach ($section->getLevels() as $level) { |
| 198 | $levelId = $level->getId(); |
| 199 | if (!in_array($levelId, $existingLevelIds, true)) { |
| 200 | $ordering[$sectionId]['levels'][$levelId] = $nextLevelIndexes[$sectionId]++; |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | return $ordering; |
| 206 | } |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | } |
| 212 |