Passed
Pull Request — master (#2053)
by Janko
22:12 queued 10:55
created

ShipMover::travelFlightRoute()   B

Complexity

Conditions 11
Paths 9

Size

Total Lines 84
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 11.0619

Importance

Changes 0
Metric Value
cc 11
eloc 46
c 0
b 0
f 0
nc 9
nop 5
dl 0
loc 84
ccs 46
cts 50
cp 0.92
crap 11.0619
rs 7.3166

How to fix   Long Method    Complexity   

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
namespace Stu\Module\Spacecraft\Lib\Movement;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\Collections\Collection;
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 Stu\Lib\Information\InformationWrapper;
9
use Stu\Module\PlayerSetting\Lib\UserEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Module\PlayerSetting\Lib\UserEnum 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\Module\Spacecraft\Lib\Battle\AlertDetection\AlertReactionFacadeInterface;
11
use Stu\Module\Ship\Lib\Fleet\LeaveFleetInterface;
12
use Stu\Module\Ship\Lib\ShipWrapperInterface;
13
use Stu\Module\Spacecraft\Lib\Message\MessageCollectionInterface;
14
use Stu\Module\Spacecraft\Lib\Message\MessageFactoryInterface;
15
use Stu\Module\Spacecraft\Lib\Movement\Component\PreFlight\PreFlightConditionsCheckInterface;
16
use Stu\Module\Spacecraft\Lib\Movement\Route\FlightRouteInterface;
17
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
18
use Stu\Orm\Entity\ShipInterface;
19
use Stu\Orm\Entity\SpacecraftInterface;
20
use Stu\Orm\Repository\SpacecraftRepositoryInterface;
21
22
//TODO unit tests
23
final class ShipMover implements ShipMoverInterface
24
{
25 4
    public function __construct(
26
        private SpacecraftRepositoryInterface $spacecraftRepository,
27
        private ShipMovementInformationAdderInterface $shipMovementInformationAdder,
28
        private PreFlightConditionsCheckInterface $preFlightConditionsCheck,
29
        private LeaveFleetInterface $leaveFleet,
30
        private AlertReactionFacadeInterface $alertReactionFacade,
31
        private MessageFactoryInterface $messageFactory
32 4
    ) {}
33
34 3
    #[Override]
35
    public function checkAndMove(
36
        SpacecraftWrapperInterface $leadWrapper,
37
        FlightRouteInterface $flightRoute
38
    ): MessageCollectionInterface {
39
40 3
        $messages = $this->messageFactory->createMessageCollection();
41
42 3
        $leadSpacecraft = $leadWrapper->get();
43 3
        $leadSpacecraftName = $leadSpacecraft->getName();
44 3
        $isFleetMode = $leadSpacecraft instanceof ShipInterface ? $leadSpacecraft->isFleetLeader() : false;
45
46 3
        $wrappers = $this->initWrappers($leadWrapper, $isFleetMode);
47 3
        $initialTractoredShips = $this->initTractoredShips($wrappers);
48
49
        // fly until destination arrived
50 3
        $hasTravelled = $this->travelFlightRoute(
51 3
            $leadWrapper,
52 3
            $wrappers,
53 3
            $isFleetMode,
54 3
            $flightRoute,
55 3
            $messages
56 3
        );
57
58
        //skip save and log info if flight did not happen
59 3
        if (!$hasTravelled) {
60 1
            return $messages;
61
        }
62
63
        // save all ships
64 2
        $this->saveShips($wrappers, $initialTractoredShips);
65
66
        // add post flight informations
67 2
        $this->postFlightInformations(
68 2
            $leadWrapper,
69 2
            $leadSpacecraftName,
70 2
            $wrappers,
71 2
            $flightRoute,
72 2
            $isFleetMode,
73 2
            $messages
74 2
        );
75
76 2
        return $messages;
77
    }
78
79
    /** @return Collection<int, covariant SpacecraftWrapperInterface> */
80 3
    private function initWrappers(SpacecraftWrapperInterface $leadWrapper, bool $isFleetMode): Collection
81
    {
82 3
        $fleetWrapper = $leadWrapper->getFleetWrapper();
83
84 3
        return
85 3
            $isFleetMode && $fleetWrapper !== null
86 1
            ? $fleetWrapper->getShipWrappers()
87 3
            : new ArrayCollection([$leadWrapper->get()->getId() => $leadWrapper]);
88
    }
89
90
    /** @param Collection<int, covariant SpacecraftWrapperInterface> $wrappers */
0 ignored issues
show
Bug introduced by
The type Stu\Module\Spacecraft\Lib\Movement\covariant 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...
91 3
    private function travelFlightRoute(
92
        SpacecraftWrapperInterface $leadWrapper,
93
        Collection $wrappers,
94
        bool $isFleetMode,
95
        FlightRouteInterface $flightRoute,
96
        MessageCollectionInterface $messages
97
    ): bool {
98
99 3
        $hasTravelled = false;
100 3
        $leadSpacecraft = $leadWrapper->get();
101 3
        $fleetWrapper = $leadWrapper->getFleetWrapper();
102
103 3
        $isFixedFleetMode = $isFleetMode
104 3
            && $fleetWrapper !== null
105 3
            && $fleetWrapper->get()->isFleetFixed();
106
107 3
        $activeWrappers = new ArrayCollection($wrappers->toArray());
108
109 3
        while (!$flightRoute->isDestinationArrived()) {
110 3
            $nextWaypoint = $flightRoute->getNextWaypoint();
111
112
            // nächstes Feld nicht passierbar
113 3
            if (!$nextWaypoint->getFieldType()->getPassable()) {
114
                $flightRoute->abortFlight();
115
                $messages->addInformation('Das nächste Feld kann nicht passiert werden');
116
                break;
117
            }
118
119 3
            $activeWrappers = $activeWrappers->filter(fn(SpacecraftWrapperInterface $wrapper): bool => !$wrapper->get()->isDestroyed());
120
121
            // check all flight pre conditions
122 3
            $conditionCheckResult = $this->preFlightConditionsCheck->checkPreconditions(
123 3
                $leadWrapper,
124 3
                $activeWrappers->toArray(),
125 3
                $flightRoute,
126 3
                $isFixedFleetMode
127 3
            );
128
129 3
            if (!$conditionCheckResult->isFlightPossible()) {
130 1
                $flightRoute->abortFlight();
131 1
                $messages->addInformation('Der Weiterflug wurde aus folgenden Gründen abgebrochen:');
132 1
                $this->addInformationMerge($conditionCheckResult->getInformations(), $messages);
133 1
                break;
134
            }
135
136 2
            foreach ($conditionCheckResult->getBlockedIds() as $spacecraftId) {
137 1
                $activeWrappers->remove($spacecraftId);
138
            }
139
140 2
            $hasToLeaveFleet = $leadWrapper->getFleetWrapper() !== null && !$isFleetMode;
141 2
            if ($hasToLeaveFleet) {
142
                $this->leaveFleet($leadSpacecraft, $messages);
143
            }
144
145 2
            $this->addInformationMerge($conditionCheckResult->getInformations(), $messages);
146
147
            /** @var array<array{0: SpacecraftInterface, 1: ShipWrapperInterface}> */
148 2
            $movedTractoredShipWrappers = [];
149
150
            // move every possible ship by one field
151 2
            $this->moveShipsByOneField(
152 2
                $activeWrappers,
153 2
                $flightRoute,
154 2
                $movedTractoredShipWrappers,
155 2
                $messages
156 2
            );
157 2
            $hasTravelled = true;
158
159
            // alert reaction check
160 2
            if (!$this->areAllShipsDestroyed($activeWrappers)) {
161 1
                $this->alertReactionCheck(
162 1
                    $leadWrapper,
163 1
                    $movedTractoredShipWrappers,
164 1
                    $messages
165 1
                );
166
            }
167
168 2
            if ($this->areAllShipsDestroyed($activeWrappers)) {
169 1
                $flightRoute->abortFlight();
170 1
                $messages->addInformation('Es wurden alle Schiffe zerstört');
171
            }
172
        }
173
174 3
        return $hasTravelled;
175
    }
176
177
    /**
178
     * @param Collection<int, SpacecraftWrapperInterface> $activeWrappers
179
     * @param array<array{0: SpacecraftInterface, 1: ShipWrapperInterface}> $movedTractoredShipWrappers
180
     */
181 2
    private function moveShipsByOneField(
182
        Collection $activeWrappers,
183
        FlightRouteInterface $flightRoute,
184
        array &$movedTractoredShipWrappers,
185
        MessageCollectionInterface $messages
186
    ): void {
187
188 2
        $flightRoute->enterNextWaypoint(
189 2
            $activeWrappers,
190 2
            $messages
191 2
        );
192
193 2
        foreach ($activeWrappers as $wrapper) {
194
195 2
            $tractoredShipWrapper = $wrapper->getTractoredShipWrapper();
196 2
            if ($tractoredShipWrapper !== null) {
197
                $movedTractoredShipWrappers[] = [$wrapper->get(), $tractoredShipWrapper];
198
            }
199
        }
200
    }
201
202
    /** @param array<array{0: SpacecraftInterface, 1: ShipWrapperInterface}> $movedTractoredShipWrappers */
203 1
    private function alertReactionCheck(
204
        SpacecraftWrapperInterface $leadWrapper,
205
        array $movedTractoredShipWrappers,
206
        MessageCollectionInterface $messages
207
    ): void {
208 1
        $alertRedInformations = new InformationWrapper();
209 1
        $this->alertReactionFacade->doItAll($leadWrapper, $alertRedInformations);
210
211 1
        if (!$alertRedInformations->isEmpty()) {
212
            $this->addInformationMerge($alertRedInformations->getInformations(), $messages);
213
        }
214
215
        // alert red check for tractored ships
216 1
        foreach ($movedTractoredShipWrappers as [$tractoringSpacecraft, $tractoredShipWrapper]) {
217
            if (!$tractoredShipWrapper->get()->isDestroyed()) {
218
                $alertRedInformations = new InformationWrapper();
219
                $this->alertReactionFacade->doItAll(
220
                    $tractoredShipWrapper,
221
                    $alertRedInformations,
222
                    $tractoringSpacecraft
223
                );
224
225
                if (!$alertRedInformations->isEmpty()) {
226
                    $this->addInformationMerge($alertRedInformations->getInformations(), $messages);
227
                }
228
            }
229
        }
230
    }
231
232
    /**
233
     * @param Collection<int, covariant SpacecraftWrapperInterface> $wrappers
234
     *
235
     * @return array<ShipInterface>
236
     */
237 3
    private function initTractoredShips(Collection $wrappers): array
238
    {
239 3
        $tractoredShips = [];
240
241 3
        foreach ($wrappers as $fleetShipWrapper) {
242 3
            $fleetShip = $fleetShipWrapper->get();
243
244 3
            $tractoredShip = $fleetShip->getTractoredShip();
245
            if (
246 3
                $tractoredShip !== null
247
            ) {
248
                $tractoredShips[] = $tractoredShip;
249
            }
250
        }
251
252 3
        return $tractoredShips;
253
    }
254
255
    private function leaveFleet(SpacecraftInterface $ship, MessageCollectionInterface $messages): void
256
    {
257
        if ($ship instanceof ShipInterface) {
258
            if ($this->leaveFleet->leaveFleet($ship)) {
259
                $messages->addInformationf('Die %s hat die Flotte verlassen', $ship->getName());
260
            }
261
        }
262
    }
263
264
    /**
265
     * @param Collection<int, covariant SpacecraftWrapperInterface> $wrappers
266
     * @param array<ShipInterface> $initialTractoredShips
267
     */
268 2
    private function saveShips(Collection $wrappers, array $initialTractoredShips): void
269
    {
270 2
        foreach ($wrappers as $wrapper) {
271 2
            $ship = $wrapper->get();
272 2
            if (!$ship->isDestroyed()) {
273 1
                $this->spacecraftRepository->save($ship);
274
            }
275
        }
276
277 2
        foreach ($initialTractoredShips as $tractoredShip) {
278
            $this->spacecraftRepository->save($tractoredShip);
279
        }
280
    }
281
282
    /**
283
     * @param Collection<int, covariant SpacecraftWrapperInterface> $wrappers
284
     */
285 2
    private function postFlightInformations(
286
        SpacecraftWrapperInterface $leadWrapper,
287
        string $leadSpacecraftName,
288
        Collection $wrappers,
289
        FlightRouteInterface $flightRoute,
290
        bool $isFleetMode,
291
        MessageCollectionInterface $messages
292
    ): void {
293
294
        //add tractor info
295 2
        foreach ($wrappers as $wrapper) {
296 2
            $ship = $wrapper->get();
297
298 2
            $tractoredShip = $ship->getTractoredShip();
299 2
            if ($tractoredShip !== null) {
300
                $this->shipMovementInformationAdder->pulledTractoredShip(
301
                    $ship,
302
                    $tractoredShip,
303
                    $flightRoute->getRouteMode(),
304
                    $messages
305
                );
306
            }
307
        }
308
309 2
        $leadSpacecraft = $leadWrapper->get();
310
311
        //add destination info
312 2
        if ($this->areAllShipsDestroyed($wrappers)) {
313 1
            $this->shipMovementInformationAdder->reachedDestinationDestroyed(
314 1
                $leadSpacecraft,
315 1
                $leadSpacecraftName,
316 1
                $isFleetMode,
317 1
                $flightRoute->getRouteMode(),
318 1
                $messages
319 1
            );
320
        } else {
321 1
            $this->shipMovementInformationAdder->reachedDestination(
322 1
                $leadSpacecraft,
323 1
                $isFleetMode,
324 1
                $flightRoute->getRouteMode(),
325 1
                $messages
326 1
            );
327
        }
328
329 2
        $finalDestination = $leadWrapper->get()->getLocation();
330
331
        //add info about anomalies
332 2
        foreach ($finalDestination->getAnomalies() as $anomaly) {
333
            $messages->addInformationf(
334
                '[b][color=yellow]In diesem Sektor befindet sich eine %s-Anomalie[/color][/b]',
335
                $anomaly->getAnomalyType()->getName()
336
            );
337
        }
338
        // add info about buyos
339 2
        foreach ($finalDestination->getBuoys() as $buoy) {
340
            $messages->addInformationf('[b][color=yellow]Boje entdeckt: [/color][/b]%s', $buoy->getText());
341
        }
342
    }
343
344
    /**
345
     * @param Collection<int, covariant SpacecraftWrapperInterface> $wrappers
346
     */
347 2
    private function areAllShipsDestroyed(Collection $wrappers): bool
348
    {
349 2
        return !$wrappers->exists(fn(int $key, SpacecraftWrapperInterface $wrapper): bool => !$wrapper->get()->isDestroyed());
350
    }
351
352
    /**
353
     * @param array<string> $value
354
     */
355 3
    private function addInformationMerge(array $value, MessageCollectionInterface $messages): void
356
    {
357 3
        $messages->add($this->messageFactory->createMessage(UserEnum::USER_NOONE, null, $value));
358
    }
359
}
360