Passed
Push — master ( 50ea2d...c8d4e9 )
by Janko
05:17
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 51
    #[Override]
41
    public function getByIdAndUser(
42
        int $spacecraftId,
43
        int $userId,
44
        bool $allowUplink = false,
45
        bool $checkForEntityLock = true
46
    ): Spacecraft {
47
48 51
        return $this->getByIdAndUserAndTargetIntern(
49 51
            $spacecraftId,
50 51
            $userId,
51 51
            null,
52 51
            $allowUplink,
53 51
            $checkForEntityLock
54 51
        )->getSource()->get();
55
    }
56
57 88
    #[Override]
58
    public function getWrapperByIdAndUser(
59
        int $spacecraftId,
60
        int $userId,
61
        bool $allowUplink = false,
62
        bool $checkForEntityLock = true
63
    ): SpacecraftWrapperInterface {
64
65 88
        return $this->getByIdAndUserAndTargetIntern(
66 88
            $spacecraftId,
67 88
            $userId,
68 88
            null,
69 88
            $allowUplink,
70 88
            $checkForEntityLock
71 88
        )->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 157
    private function getByIdAndUserAndTargetIntern(
96
        int $spacecraftId,
97
        int $userId,
98
        ?int $targetId,
99
        bool $allowUplink,
100
        bool $checkForEntityLock
101
    ): SourceAndTargetWrappersInterface {
102
103 157
        if ($checkForEntityLock) {
104 117
            $this->checkForEntityLock($spacecraftId);
105
        }
106
107 156
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
108 156
        if ($spacecraft === null) {
109 1
            throw new SpacecraftDoesNotExistException('Raumfahrzeug existiert nicht!');
110
        }
111 155
        $this->checkviolations($spacecraft, $userId, $allowUplink);
112
113 151
        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 155
    private function checkviolations(Spacecraft $spacecraft, int $userId, bool $allowUplink): void
124
    {
125 155
        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 154
    private function acquireSemaphores(Spacecraft $spacecraft, ?int $targetId): SourceAndTargetWrappersInterface
167
    {
168 154
        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 154
        StuLogger::log(sprintf(
174 154
            'Acquiring main semaphore for user %d and spacecraft %d%s',
175 154
            $spacecraft->getUser()->getId(),
176 154
            $spacecraft->getId(),
177 154
            $targetId !== null ? ', target ' . $targetId : ''
178 154
        ), LogTypeEnum::SEMAPHORE);
179
180 154
        $startTime = microtime(true);
181 154
        $mainSema = $this->semaphoreUtil->acquireSemaphore(SemaphoreConstants::MAIN_SHIP_SEMAPHORE_KEY);
182
183 154
        StuLogger::log(sprintf(
184 154
            'Main semaphore acquired for user %d, waited %F seconds',
185 154
            $spacecraft->getUser()->getId(),
186 154
            microtime(true) - $startTime
187 154
        ), LogTypeEnum::SEMAPHORE);
188
189 154
        StuLogger::log(sprintf(
190 154
            'Acquiring spacecraft semaphore for user %d and spacecraft %d',
191 154
            $spacecraft->getUser()->getId(),
192 154
            $spacecraft->getId()
193 154
        ), LogTypeEnum::SEMAPHORE);
194
195 154
        $startTime = microtime(true);
196 154
        $wrapper = $this->acquireSemaphoreForSpacecraft($spacecraft);
197 154
        if ($wrapper === null) {
198
            throw new RuntimeException('wrapper should not be null here');
199
        }
200
201 154
        StuLogger::log(sprintf(
202 154
            'Spacecraft semaphore acquired for user %d and spacecraft %d, waited %F seconds',
203 154
            $spacecraft->getUser()->getId(),
204 154
            $spacecraft->getId(),
205 154
            microtime(true) - $startTime
206 154
        ), LogTypeEnum::SEMAPHORE);
207
208 154
        $result = new SourceAndTargetWrappers($wrapper);
209
210 154
        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 154
        $this->semaphoreUtil->releaseSemaphore($mainSema);
231 154
        StuLogger::log(sprintf(
232 154
            'Main semaphore released for user %d',
233 154
            $spacecraft->getUser()->getId()
234 154
        ), LogTypeEnum::SEMAPHORE);
235
236 154
        return $result;
237
    }
238
239 154
    private function acquireSemaphoreForSpacecraft(Spacecraft|int $spacecraft): ?SpacecraftWrapperInterface
240
    {
241 154
        $spacecraft = $spacecraft instanceof Spacecraft
242 154
            ? $spacecraft
243 21
            : $this->spacecraftRepository->find($spacecraft);
244
245 154
        if ($spacecraft === null) {
246 2
            return null;
247
        }
248
249 154
        $key = $spacecraft->getUser()->getId();
250 154
        StuLogger::log(sprintf(
251 154
            'spacecraft %d with key %d',
252 154
            $spacecraft->getId(),
253 154
            $key
254 154
        ), LogTypeEnum::SEMAPHORE);
255 154
        $this->semaphoreUtil->acquireSemaphore($key);
256
257 154
        return $this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft);
258
    }
259
}
260