Passed
Push — dev ( 2f6208...3247a5 )
by Nico
35:29
created

ShipLoader::acquireSemaphores()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5.0909

Importance

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