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

SpacecraftLoader::acquireSemaphores()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 71
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 50
CRAP Score 6.002

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 6
eloc 51
c 2
b 0
f 1
nc 4
nop 2
dl 0
loc 71
ccs 50
cts 52
cp 0.9615
crap 6.002
rs 8.4468

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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