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