Passed
Push — master ( 6d626d...5de675 )
by Janko
09:20
created

SpacecraftLoader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 0
c 0
b 0
f 0
nc 1
nop 6
dl 0
loc 8
ccs 2
cts 2
cp 1
crap 1
rs 10
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\GameControllerInterface;
16
use Stu\Module\Control\SemaphoreUtilInterface;
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 SpacecraftRepositoryInterface $spacecraftRepository,
33
        private CrewAssignmentRepositoryInterface $crewAssignmentRepository,
34
        private SemaphoreUtilInterface $semaphoreUtil,
35
        private GameControllerInterface $game,
36
        private SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
37
        private LockManagerInterface $lockManager
38 11
    ) {}
39
40 21
    #[Override]
41
    public function getByIdAndUser(
42
        int $spacecraftId,
43
        int $userId,
44
        bool $allowUplink = false,
45
        bool $checkForEntityLock = true
46
    ): Spacecraft {
47
48 21
        return $this->getByIdAndUserAndTargetIntern(
49 21
            $spacecraftId,
50 21
            $userId,
51 21
            null,
52 21
            $allowUplink,
53 21
            $checkForEntityLock
54 21
        )->getSource()->get();
55
    }
56
57 24
    #[Override]
58
    public function getWrapperByIdAndUser(
59
        int $spacecraftId,
60
        int $userId,
61
        bool $allowUplink = false,
62
        bool $checkForEntityLock = true
63
    ): SpacecraftWrapperInterface {
64
65 24
        return $this->getByIdAndUserAndTargetIntern(
66 24
            $spacecraftId,
67 24
            $userId,
68 24
            null,
69 24
            $allowUplink,
70 24
            $checkForEntityLock
71 24
        )->getSource();
72
    }
73
74 3
    #[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 3
        return $this->getByIdAndUserAndTargetIntern(
84 3
            $spacecraftId,
85 3
            $userId,
86 3
            $targetId,
87 3
            $allowUplink,
88 3
            $checkForEntityLock
89 3
        );
90
    }
91
92
    /**
93
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
94
     */
95 46
    private function getByIdAndUserAndTargetIntern(
96
        int $spacecraftId,
97
        int $userId,
98
        ?int $targetId,
99
        bool $allowUplink,
100
        bool $checkForEntityLock
101
    ): SourceAndTargetWrappersInterface {
102
103 46
        if ($checkForEntityLock) {
104 13
            $this->checkForEntityLock($spacecraftId);
105
        }
106
107 45
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
108 45
        if ($spacecraft === null) {
109 1
            throw new SpacecraftDoesNotExistException('Spacecraft does not exist!');
110
        }
111 44
        $this->checkviolations($spacecraft, $userId, $allowUplink);
112
113 40
        return $this->acquireSemaphores($spacecraft, $targetId);
114
    }
115
116 13
    private function checkForEntityLock(int $spacecraftId): void
117
    {
118 13
        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 44
    private function checkviolations(Spacecraft $spacecraft, int $userId, bool $allowUplink): void
124
    {
125 44
        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 10
    #[Override]
143
    public function find(int $spacecraftId, bool $checkForEntityLock = true): ?SpacecraftWrapperInterface
144
    {
145 10
        if ($checkForEntityLock) {
146
            $this->checkForEntityLock($spacecraftId);
147
        }
148
149 10
        $spacecraft = $this->spacecraftRepository->find($spacecraftId);
150 10
        if ($spacecraft === null) {
151
            return null;
152
        }
153
154 10
        return $this->acquireSemaphores($spacecraft, null)->getSource();
155
    }
156
157
    #[Override]
158
    public function save(Spacecraft $spacecraft): void
159
    {
160
        $this->spacecraftRepository->save($spacecraft);
161
    }
162
163
    /**
164
     * @return SourceAndTargetWrappersInterface<SpacecraftWrapperInterface>
165
     */
166 42
    private function acquireSemaphores(Spacecraft $spacecraft, ?int $targetId): SourceAndTargetWrappersInterface
167
    {
168 42
        if ($targetId === null && $this->game->isSemaphoreAlreadyAcquired($spacecraft->getUser()->getId())) {
169
            return new SourceAndTargetWrappers($this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft));
170
        }
171
172
        //main spacecraft sema on
173 42
        $mainSema = $this->semaphoreUtil->acquireSemaphore(SemaphoreConstants::MAIN_SHIP_SEMAPHORE_KEY);
174
175 42
        $wrapper = $this->acquireSemaphoreForSpacecraft($spacecraft, null);
176 42
        if ($wrapper === null) {
177
            throw new RuntimeException('wrapper should not be null here');
178
        }
179 42
        $result = new SourceAndTargetWrappers($wrapper);
180
181 42
        if ($targetId !== null) {
182 3
            $result->setTarget($this->acquireSemaphoreForSpacecraft(null, $targetId));
183
        }
184
185
        //main spacecraft sema off
186 42
        $this->semaphoreUtil->releaseSemaphore($mainSema);
187
188 42
        return $result;
189
    }
190
191 42
    private function acquireSemaphoreForSpacecraft(?Spacecraft $spacecraft, ?int $spacecraftId): ?SpacecraftWrapperInterface
192
    {
193 42
        if ($spacecraft === null && $spacecraftId === null) {
194
            return null;
195
        }
196
197 42
        if ($spacecraft === null) {
198 3
            $spacecraft = $this->spacecraftRepository->find($spacecraftId);
199
        }
200
201 42
        if ($spacecraft === null) {
202 1
            return null;
203
        }
204
205 42
        $key = $spacecraft->getUser()->getId();
206 42
        $this->semaphoreUtil->acquireSemaphore($key);
207
208 42
        return $this->spacecraftWrapperFactory->wrapSpacecraft($spacecraft);
209
    }
210
}
211