Passed
Pull Request — master (#1716)
by Nico
23:15
created

ShipLoader::acquireSemaphoreForShip()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.0187

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 5
nop 2
dl 0
loc 18
ccs 10
cts 11
cp 0.9091
crap 5.0187
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\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\Ship\System\ShipSystemTypeEnum;
10
use Stu\Exception\AccessViolation;
11
use Stu\Exception\EntityLockedException;
12
use Stu\Exception\ShipDoesNotExistException;
13
use Stu\Exception\ShipIsDestroyedException;
14
use Stu\Exception\UnallowedUplinkOperation;
15
use Stu\Module\Control\GameControllerInterface;
16
use Stu\Module\Control\SemaphoreUtilInterface;
17
use Stu\Module\Tick\Lock\LockManagerInterface;
18
use Stu\Module\Tick\Lock\LockTypeEnum;
19
use Stu\Orm\Entity\ShipInterface;
20
use Stu\Orm\Repository\ShipRepositoryInterface;
21
22
final class ShipLoader implements ShipLoaderInterface
23
{
24
    private ShipRepositoryInterface $shipRepository;
25
26
    private SemaphoreUtilInterface $semaphoreUtil;
27
28
    private GameControllerInterface $game;
29
30
    private ShipWrapperFactoryInterface $shipWrapperFactory;
31
32
    private LockManagerInterface $lockManager;
33
34 12
    public function __construct(
35
        ShipRepositoryInterface $shipRepository,
36
        SemaphoreUtilInterface $semaphoreUtil,
37
        GameControllerInterface $game,
38
        ShipWrapperFactoryInterface $shipWrapperFactory,
39
        LockManagerInterface $lockManager
40
    ) {
41 12
        $this->shipRepository = $shipRepository;
42 12
        $this->semaphoreUtil = $semaphoreUtil;
43 12
        $this->game = $game;
44 12
        $this->shipWrapperFactory = $shipWrapperFactory;
45 12
        $this->lockManager = $lockManager;
46
    }
47
48 8
    public function getByIdAndUser(
49
        int $shipId,
50
        int $userId,
51
        bool $allowUplink = false,
52
        bool $checkForEntityLock = true
53
    ): ShipInterface {
54 8
        return $this->getByIdAndUserAndTargetIntern(
55 8
            $shipId,
56 8
            $userId,
57 8
            null,
58 8
            $allowUplink,
59 8
            $checkForEntityLock
60 8
        )->getSource()->get();
61
    }
62
63 1
    public function getWrapperByIdAndUser(
64
        int $shipId,
65
        int $userId,
66
        bool $allowUplink = false,
67
        bool $checkForEntityLock = true
68
    ): ShipWrapperInterface {
69 1
        return $this->getByIdAndUserAndTargetIntern(
70 1
            $shipId,
71 1
            $userId,
72 1
            null,
73 1
            $allowUplink,
74 1
            $checkForEntityLock
75 1
        )->getSource();
76
    }
77
78 2
    public function getWrappersBySourceAndUserAndTarget(
79
        int $shipId,
80
        int $userId,
81
        int $targetId,
82
        bool $allowUplink = false,
83
        bool $checkForEntityLock = true
84
    ): SourceAndTargetWrappersInterface {
85 2
        return $this->getByIdAndUserAndTargetIntern(
86 2
            $shipId,
87 2
            $userId,
88 2
            $targetId,
89 2
            $allowUplink,
90 2
            $checkForEntityLock
91 2
        );
92
    }
93
94 11
    private function getByIdAndUserAndTargetIntern(
95
        int $shipId,
96
        int $userId,
97
        ?int $targetId,
98
        bool $allowUplink,
99
        bool $checkForEntityLock
100
    ): SourceAndTargetWrappersInterface {
101
102 11
        if ($checkForEntityLock) {
103 11
            $this->checkForEntityLock($shipId);
104
        }
105
106 10
        $ship = $this->shipRepository->find($shipId);
107 10
        if ($ship === null) {
108 1
            throw new ShipDoesNotExistException(_('Ship does not exist!'));
109
        }
110 9
        $this->checkviolations($ship, $userId, $allowUplink);
111
112 4
        return $this->acquireSemaphores($ship, $targetId);
113
    }
114
115 11
    private function checkForEntityLock(int $shipId): void
116
    {
117 11
        if ($this->lockManager->isLocked($shipId, LockTypeEnum::SHIP_GROUP)) {
118 1
            throw new EntityLockedException('Tick läuft gerade, Zugriff auf Schiff ist daher blockiert');
119
        }
120
    }
121
122 9
    private function checkviolations(ShipInterface $ship, int $userId, bool $allowUplink): void
123
    {
124 9
        if ($ship->isDestroyed()) {
125 1
            throw new ShipIsDestroyedException(_('Ship is destroyed!'));
126
        }
127
128 8
        if ($ship->getUser()->getId() !== $userId) {
129 4
            if ($ship->hasCrewmanOfUser($userId)) {
130 3
                if (!$allowUplink) {
131 1
                    throw new UnallowedUplinkOperation(_('This Operation is not allowed via uplink!'));
132
                }
133 2
                if (!$ship->getSystemState(ShipSystemTypeEnum::SYSTEM_UPLINK)) {
134 1
                    throw new UnallowedUplinkOperation(_('Uplink is not activated!'));
135
                }
136 1
                if ($ship->getUser()->isVacationRequestOldEnough()) {
137 1
                    throw new UnallowedUplinkOperation(_('Owner is on vacation!'));
138
                }
139
            } else {
140 1
                throw new AccessViolation(sprintf("Ship owned by another user (%d)! Fool: %d", $ship->getUser()->getId(), $userId));
141
            }
142
        }
143
    }
144
145
    public function find(int $shipId, bool $checkForEntityLock = true): ?ShipWrapperInterface
146
    {
147
        if ($checkForEntityLock) {
148
            $this->checkForEntityLock($shipId);
149
        }
150
151
        $ship = $this->shipRepository->find($shipId);
152
        if ($ship === null) {
153
            return null;
154
        }
155
156
        return $this->acquireSemaphores($ship, null)->getSource();
157
    }
158
159
    public function save(ShipInterface $ship): void
160
    {
161
        $this->shipRepository->save($ship);
162
    }
163
164 4
    private function acquireSemaphores(ShipInterface $ship, ?int $targetId): SourceAndTargetWrappersInterface
165
    {
166 4
        if ($targetId === null && $this->game->isSemaphoreAlreadyAcquired($ship->getUser()->getId())) {
167
            return new SourceAndTargetWrappers($this->shipWrapperFactory->wrapShip($ship));
168
        }
169
170
        //main ship sema on
171 4
        $mainSema = $this->semaphoreUtil->getSemaphore(SemaphoreConstants::MAIN_SHIP_SEMAPHORE_KEY);
172 4
        $this->semaphoreUtil->acquireMainSemaphore($mainSema);
173
174 4
        $wrapper = $this->acquireSemaphoreForShip($ship, null);
175 4
        if ($wrapper === null) {
176
            throw new RuntimeException('wrapper should not be null here');
177
        }
178 4
        $result = new SourceAndTargetWrappers($wrapper);
179
180 4
        if ($targetId !== null) {
181 2
            $result->setTarget($this->acquireSemaphoreForShip(null, $targetId));
182
        }
183
184
        //main ship sema off
185 4
        $this->semaphoreUtil->releaseSemaphore($mainSema);
186
187 4
        return $result;
188
    }
189
190 4
    private function acquireSemaphoreForShip(?ShipInterface $ship, ?int $shipId): ?ShipWrapperInterface
191
    {
192 4
        if ($ship === null && $shipId === null) {
193
            return null;
194
        }
195
196 4
        if ($ship === null) {
197 2
            $ship = $this->shipRepository->find($shipId);
198
        }
199
200 4
        if ($ship === null) {
201 1
            return null;
202
        }
203
204 4
        $key = $ship->getUser()->getId();
205 4
        $semaphore = $this->semaphoreUtil->getSemaphore($key);
206 4
        $this->semaphoreUtil->acquireSemaphore($key, $semaphore); //prüft ob schon genommen
207 4
        return $this->shipWrapperFactory->wrapShip($ship);
208
    }
209
}
210