Passed
Pull Request — master (#2257)
by Janko
10:35 queued 05:28
created

SpacecraftLoader::getByIdAndUserAndTargetIntern()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 4
nop 5
dl 0
loc 19
ccs 8
cts 8
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Spacecraft\Lib;
6
7
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use RuntimeException;
9
use Stu\Component\Game\SemaphoreConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\SemaphoreConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
11
use Stu\Exception\AccessViolationException;
12
use Stu\Exception\EntityLockedException;
13
use Stu\Exception\SpacecraftDoesNotExistException;
14
use Stu\Exception\UnallowedUplinkOperationException;
15
use Stu\Module\Control\SemaphoreUtilInterface;
16
use Stu\Module\Logging\LogTypeEnum;
17
use Stu\Module\Logging\StuLogger;
18
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
19
use Stu\Module\Spacecraft\Lib\SourceAndTargetWrappers;
20
use Stu\Module\Spacecraft\Lib\SourceAndTargetWrappersInterface;
21
use Stu\Module\Tick\Lock\LockManagerInterface;
22
use Stu\Module\Tick\Lock\LockTypeEnum;
23
use Stu\Orm\Entity\Spacecraft;
24
use Stu\Orm\Repository\CrewAssignmentRepositoryInterface;
25
use Stu\Orm\Repository\SpacecraftRepositoryInterface;
26
27
/**
28
 * @implements SpacecraftLoaderInterface<SpacecraftWrapperInterface>
29
 */
30
final class SpacecraftLoader implements SpacecraftLoaderInterface
31
{
32 11
    public function __construct(
33
        private readonly SpacecraftRepositoryInterface $spacecraftRepository,
34
        private readonly CrewAssignmentRepositoryInterface $crewAssignmentRepository,
35
        private readonly SemaphoreUtilInterface $semaphoreUtil,
36
        private readonly SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
37
        private readonly LockManagerInterface $lockManager
38 11
    ) {}
39
40 47
    #[Override]
41
    public function getByIdAndUser(
42
        int $spacecraftId,
43
        int $userId,
44
        bool $allowUplink = false,
45
        bool $checkForEntityLock = true
46
    ): Spacecraft {
47
48 47
        return $this->getByIdAndUserAndTargetIntern(
49 47
            $spacecraftId,
50 47
            $userId,
51 47
            null,
52 47
            $allowUplink,
53 47
            $checkForEntityLock
54 47
        )->getSource()->get();
55
    }
56
57 87
    #[Override]
58
    public function getWrapperByIdAndUser(
59
        int $spacecraftId,
60
        int $userId,
61
        bool $allowUplink = false,
62
        bool $checkForEntityLock = true
63
    ): SpacecraftWrapperInterface {
64
65 87
        return $this->getByIdAndUserAndTargetIntern(
66 87
            $spacecraftId,
67 87
            $userId,
68 87
            null,
69 87
            $allowUplink,
70 87
            $checkForEntityLock
71 87
        )->getSource();
72
    }
73
74 21
    #[Override]
75
    public function getWrappersBySourceAndUserAndTarget(
76
        int $spacecraftId,
77
        int $userId,
78
        int $targetId,
79
        bool $allowUplink = false,
80
        bool $checkForEntityLock = true
81
    ): SourceAndTargetWrappersInterface {
82
83 21
        return $this->getByIdAndUserAndTargetIntern(
84 21
            $spacecraftId,
85 21
            $userId,
86 21
            $targetId,
87 21
            $allowUplink,
88 21
            $checkForEntityLock
89 21
        );
90
    }
91
92
    /**
93
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
94
     */
95 153
    private function getByIdAndUserAndTargetIntern(
96
        int $spacecraftId,
97
        int $userId,
98
        ?int $targetId,
99
        bool $allowUplink,
100
        bool $checkForEntityLock
101
    ): SourceAndTargetWrappersInterface {
102
103 153
        if ($checkForEntityLock) {
104 117
            $this->checkForEntityLock($spacecraftId);
105
        }
106
107 152
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
108 152
        if ($spacecraft === null) {
109 1
            throw new SpacecraftDoesNotExistException('Raumfahrzeug existiert nicht!');
110
        }
111 151
        $this->checkviolations($spacecraft, $userId, $allowUplink);
112
113 147
        return $this->acquireSemaphores($spacecraft, $targetId);
114
    }
115
116 119
    private function checkForEntityLock(int $spacecraftId): void
117
    {
118 119
        if ($this->lockManager->isLocked($spacecraftId, LockTypeEnum::SHIP_GROUP)) {
119 1
            throw new EntityLockedException('Tick läuft gerade, Zugriff auf Schiff ist daher blockiert');
120
        }
121
    }
122
123 151
    private function checkviolations(Spacecraft $spacecraft, int $userId, bool $allowUplink): void
124
    {
125 151
        if ($spacecraft->getUser()->getId() !== $userId) {
126 4
            if ($this->crewAssignmentRepository->hasCrewmanOfUser($spacecraft, $userId)) {
127 3
                if (!$allowUplink) {
128 1
                    throw new UnallowedUplinkOperationException(_('This Operation is not allowed via uplink!'));
129
                }
130 2
                if (!$spacecraft->getSystemState(SpacecraftSystemTypeEnum::UPLINK)) {
131 1
                    throw new UnallowedUplinkOperationException(_('Uplink is not activated!'));
132
                }
133 1
                if ($spacecraft->getUser()->isVacationRequestOldEnough()) {
134 1
                    throw new UnallowedUplinkOperationException(_('Owner is on vacation!'));
135
                }
136
            } else {
137 1
                throw new AccessViolationException(sprintf("Spacecraft owned by another user (%d)! Fool: %d", $spacecraft->getUser()->getId(), $userId));
138
            }
139
        }
140
    }
141
142 15
    #[Override]
143
    public function find(int $spacecraftId, bool $checkForEntityLock = true): ?SpacecraftWrapperInterface
144
    {
145 15
        if ($checkForEntityLock) {
146 5
            $this->checkForEntityLock($spacecraftId);
147
        }
148
149 15
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
150 15
        if ($spacecraft === null) {
151 1
            return null;
152
        }
153
154 14
        return $this->acquireSemaphores($spacecraft, null)->getSource();
155
    }
156
157 3
    #[Override]
158
    public function save(Spacecraft $spacecraft): void
159
    {
160 3
        $this->spacecraftRepository->save($spacecraft);
161
    }
162
163
    /**
164
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
165
     */
166 150
    private function acquireSemaphores(Spacecraft $spacecraft, ?int $targetId): SourceAndTargetWrappersInterface
167
    {
168 150
        if ($targetId === null && $this->semaphoreUtil->isSemaphoreAlreadyAcquired($spacecraft->getUser()->getId())) {
169
            return new SourceAndTargetWrappers($this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft));
170
        }
171
172
        //main spacecraft sema on
173 150
        StuLogger::log(sprintf(
174 150
            'Acquiring main semaphore for user %d and spacecraft %d%s',
175 150
            $spacecraft->getUser()->getId(),
176 150
            $spacecraft->getId(),
177 150
            $targetId !== null ? ', target ' . $targetId : ''
178 150
        ), LogTypeEnum::SEMAPHORE);
179
180 150
        $startTime = microtime(true);
181 150
        $mainSema = $this->semaphoreUtil->acquireSemaphore(SemaphoreConstants::MAIN_SHIP_SEMAPHORE_KEY);
182
183 150
        StuLogger::log(sprintf(
184 150
            'Main semaphore acquired for user %d, waited %F seconds',
185 150
            $spacecraft->getUser()->getId(),
186 150
            microtime(true) - $startTime
187 150
        ), LogTypeEnum::SEMAPHORE);
188
189 150
        StuLogger::log(sprintf(
190 150
            'Acquiring spacecraft semaphore for user %d and spacecraft %d',
191 150
            $spacecraft->getUser()->getId(),
192 150
            $spacecraft->getId()
193 150
        ), LogTypeEnum::SEMAPHORE);
194
195 150
        $startTime = microtime(true);
196 150
        $wrapper = $this->acquireSemaphoreForSpacecraft($spacecraft);
197 150
        if ($wrapper === null) {
198
            throw new RuntimeException('wrapper should not be null here');
199
        }
200
201 150
        StuLogger::log(sprintf(
202 150
            'Spacecraft semaphore acquired for user %d and spacecraft %d, waited %F seconds',
203 150
            $spacecraft->getUser()->getId(),
204 150
            $spacecraft->getId(),
205 150
            microtime(true) - $startTime
206 150
        ), LogTypeEnum::SEMAPHORE);
207
208 150
        $result = new SourceAndTargetWrappers($wrapper);
209
210 150
        if ($targetId !== null) {
211
212 21
            StuLogger::log(sprintf(
213 21
                'Acquiring target spacecraft semaphore for user %d and target %d',
214 21
                $spacecraft->getUser()->getId(),
215 21
                $targetId
216 21
            ), LogTypeEnum::SEMAPHORE);
217
218 21
            $startTime = microtime(true);
219 21
            $result->setTarget($this->acquireSemaphoreForSpacecraft($targetId));
220
221 21
            StuLogger::log(sprintf(
222 21
                'Target spacecraft semaphore acquired for user %d and target %d, waited %F seconds',
223 21
                $spacecraft->getUser()->getId(),
224 21
                $targetId,
225 21
                microtime(true) - $startTime
226 21
            ), LogTypeEnum::SEMAPHORE);
227
        }
228
229
        //main spacecraft sema off
230 150
        $this->semaphoreUtil->releaseSemaphore($mainSema);
231 150
        StuLogger::log(sprintf(
232 150
            'Main semaphore released for user %d',
233 150
            $spacecraft->getUser()->getId()
234 150
        ), LogTypeEnum::SEMAPHORE);
235
236 150
        return $result;
237
    }
238
239 150
    private function acquireSemaphoreForSpacecraft(Spacecraft|int $spacecraft): ?SpacecraftWrapperInterface
240
    {
241 150
        $spacecraft = $spacecraft instanceof Spacecraft
242 150
            ? $spacecraft
243 21
            : $this->spacecraftRepository->find($spacecraft);
244
245 150
        if ($spacecraft === null) {
246 2
            return null;
247
        }
248
249 150
        $key = $spacecraft->getUser()->getId();
250 150
        $this->semaphoreUtil->acquireSemaphore($key);
251
252 150
        return $this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft);
253
    }
254
}
255