Passed
Push — master ( 288b46...98b0e3 )
by Nico
31:30 queued 08:00
created

ShipRemover::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 17
c 0
b 0
f 0
nc 1
nop 17
dl 0
loc 36
ccs 18
cts 18
cp 1
crap 1
rs 9.7

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib;
6
7
use RuntimeException;
8
use Stu\Component\Ship\ShipRumpEnum;
9
use Stu\Component\Ship\ShipStateEnum;
10
use Stu\Component\Ship\SpacecraftTypeEnum;
11
use Stu\Component\Ship\Storage\ShipStorageManagerInterface;
12
use Stu\Component\Ship\System\ShipSystemManagerInterface;
13
use Stu\Component\Ship\System\ShipSystemTypeEnum;
14
use Stu\Module\Message\Lib\PrivateMessageFolderSpecialEnum;
15
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
16
use Stu\Module\PlayerSetting\Lib\UserEnum;
17
use Stu\Module\Ship\Lib\Crew\ShipLeaverInterface;
18
use Stu\Module\Ship\Lib\Fleet\LeaveFleetInterface;
19
use Stu\Module\Ship\Lib\Torpedo\ClearTorpedoInterface;
20
use Stu\Module\Ship\View\ShowShip\ShowShip;
21
use Stu\Orm\Entity\ShipInterface;
22
use Stu\Orm\Entity\TradePostInterface;
23
use Stu\Orm\Repository\CrewRepositoryInterface;
24
use Stu\Orm\Repository\ShipCrewRepositoryInterface;
25
use Stu\Orm\Repository\ShipRepositoryInterface;
26
use Stu\Orm\Repository\ShipRumpRepositoryInterface;
27
use Stu\Orm\Repository\ShipSystemRepositoryInterface;
28
use Stu\Orm\Repository\StorageRepositoryInterface;
29
use Stu\Orm\Repository\TradePostRepositoryInterface;
30
use Stu\Orm\Repository\UserRepositoryInterface;
31
32
//TODO unit tests
33
final class ShipRemover implements ShipRemoverInterface
34
{
35
    private ShipSystemRepositoryInterface $shipSystemRepository;
36
37
    private StorageRepositoryInterface $storageRepository;
38
39
    private ShipStorageManagerInterface $shipStorageManager;
40
41
    private CrewRepositoryInterface $crewRepository;
42
43
    private ShipCrewRepositoryInterface $shipCrewRepository;
44
45
    private ShipRepositoryInterface $shipRepository;
46
47
    private UserRepositoryInterface $userRepository;
48
49
    private ShipRumpRepositoryInterface $shipRumpRepository;
50
51
    private ShipSystemManagerInterface $shipSystemManager;
52
53
    private ShipLeaverInterface $shipLeaver;
54
55
    private AstroEntryLibInterface $astroEntryLib;
56
57
    private ClearTorpedoInterface $clearTorpedo;
58
59
    private TradePostRepositoryInterface $tradePostRepository;
60
61
    private ShipStateChangerInterface $shipStateChanger;
62
63
    private ShipWrapperFactoryInterface $shipWrapperFactory;
64
65
    private LeaveFleetInterface $leaveFleet;
66
67
    private PrivateMessageSenderInterface $privateMessageSender;
68
69 1
    public function __construct(
70
        ShipSystemRepositoryInterface $shipSystemRepository,
71
        StorageRepositoryInterface $storageRepository,
72
        ShipStorageManagerInterface $shipStorageManager,
73
        CrewRepositoryInterface $crewRepository,
74
        ShipCrewRepositoryInterface $shipCrewRepository,
75
        ShipRepositoryInterface $shipRepository,
76
        UserRepositoryInterface $userRepository,
77
        ShipRumpRepositoryInterface $shipRumpRepository,
78
        ShipSystemManagerInterface $shipSystemManager,
79
        ShipLeaverInterface $shipLeaver,
80
        AstroEntryLibInterface $astroEntryLib,
81
        ClearTorpedoInterface $clearTorpedo,
82
        TradePostRepositoryInterface $tradePostRepository,
83
        ShipStateChangerInterface $shipStateChanger,
84
        ShipWrapperFactoryInterface $shipWrapperFactory,
85
        LeaveFleetInterface $leaveFleet,
86
        PrivateMessageSenderInterface $privateMessageSender
87
    ) {
88 1
        $this->shipSystemRepository = $shipSystemRepository;
89 1
        $this->storageRepository = $storageRepository;
90 1
        $this->shipStorageManager = $shipStorageManager;
91 1
        $this->crewRepository = $crewRepository;
92 1
        $this->shipCrewRepository = $shipCrewRepository;
93 1
        $this->shipRepository = $shipRepository;
94 1
        $this->userRepository = $userRepository;
95 1
        $this->shipRumpRepository = $shipRumpRepository;
96 1
        $this->shipSystemManager = $shipSystemManager;
97 1
        $this->shipLeaver = $shipLeaver;
98 1
        $this->astroEntryLib = $astroEntryLib;
99 1
        $this->clearTorpedo = $clearTorpedo;
100 1
        $this->tradePostRepository = $tradePostRepository;
101 1
        $this->shipStateChanger = $shipStateChanger;
102 1
        $this->shipWrapperFactory = $shipWrapperFactory;
103 1
        $this->leaveFleet = $leaveFleet;
104 1
        $this->privateMessageSender = $privateMessageSender;
105
    }
106
107
    public function destroy(ShipWrapperInterface $wrapper): ?string
108
    {
109
        $trumfieldRump = $this->shipRumpRepository->find(ShipRumpEnum::SHIP_CATEGORY_TRUMFIELD);
110
        if ($trumfieldRump === null) {
111
            throw new RuntimeException('trumfield rump missing');
112
        }
113
114
        $msg = null;
115
116
        $ship = $wrapper->get();
117
        $this->shipSystemManager->deactivateAll($wrapper);
118
        $user = $ship->getUser();
119
120
        $this->leaveFleet->leaveFleet($ship);
121
122
        if ($ship->getState() === ShipStateEnum::SHIP_STATE_ASTRO_FINALIZING) {
123
            $this->astroEntryLib->cancelAstroFinalizing($ship);
124
        }
125
126
        //leave ship if there is crew
127
        if ($ship->getCrewCount() > 0) {
128
            $msg = $this->shipLeaver->evacuate($wrapper);
129
        }
130
131
        /**
132
         * this is buggy :(
133
         * throws ORMInvalidArgumentException
134
         *
135
         if ($ship->getRump()->isEscapePods())
136
         {
137
             $this->remove($ship);
138
             return $msg;
139
            }
140
         */
141
142
        $this->leaveSomeIntactModules($ship);
143
144
        $ship->setFormerRumpId($ship->getRump()->getId());
145
        $ship->setRump($trumfieldRump);
146
        $ship->setHuell((int) ceil($ship->getMaxHull() / 20));
147
        $ship->setUser($this->userRepository->getFallbackUser());
148
        $ship->setBuildplan(null);
149
        $ship->setSpacecraftType(SpacecraftTypeEnum::SPACECRAFT_TYPE_OTHER);
150
        $ship->setShield(0);
151
        $ship->setAlertStateGreen();
152
        $ship->setInfluenceArea(null);
153
        $ship->setDockedTo(null);
154
        $oldName = $ship->getName();
155
        $ship->setName(_('Trümmer'));
156
        $ship->setIsDestroyed(true);
157
        $this->shipStateChanger->changeShipState($wrapper, ShipStateEnum::SHIP_STATE_DESTROYED);
158
159
        // delete ship systems
160
        $this->shipSystemRepository->truncateByShip($ship->getId());
161
        $ship->getSystems()->clear();
162
163
        if ($user->getState() === UserEnum::USER_STATE_COLONIZATION_SHIP) {
164
            $user->setState(UserEnum::USER_STATE_UNCOLONIZED);
165
            $this->userRepository->save($user);
166
        }
167
168
        // delete torpedo storage
169
        $this->clearTorpedo->clearTorpedoStorage($wrapper);
170
171
        // delete trade post stuff
172
        if ($ship->getTradePost() !== null) {
173
            $this->destroyTradepost($ship->getTradePost());
174
            $ship->setTradePost(null);
175
        }
176
177
        // change storage owner
178
        $this->orphanizeStorage($ship);
179
180
        $this->shipRepository->save($ship);
181
182
        // undock docked ships
183
        foreach ($ship->getDockedShips() as $dockedShip) {
184
            $dockedShip->setDockedTo(null);
185
            $this->shipRepository->save($dockedShip);
186
        }
187
188
        // clear tractor status
189
190
        $tractoringShipWrapper = $wrapper->getTractoringShipWrapper();
191
        if ($tractoringShipWrapper !== null) {
192
            $tractoringShip = $tractoringShipWrapper->get();
193
            $this->shipSystemManager->deactivate($tractoringShipWrapper, ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM, true);
194
195
            $href = sprintf('ship.php?%s=1&id=%d', ShowShip::VIEW_IDENTIFIER, $tractoringShip->getId());
196
197
            $this->privateMessageSender->send(
198
                UserEnum::USER_NOONE,
199
                $tractoringShip->getUser()->getId(),
200
                sprintf('Die im Traktorstrahl der %s befindliche %s wurde zerstört', $tractoringShip->getName(), $oldName),
201
                $tractoringShip->isBase() ? PrivateMessageFolderSpecialEnum::PM_SPECIAL_STATION : PrivateMessageFolderSpecialEnum::PM_SPECIAL_SHIP,
202
                $href
203
            );
204
        }
205
206
        // reset tracker devices
207
        $this->resetTrackerDevices($ship->getId());
208
209
        return $msg;
210
    }
211
212
    private function resetTrackerDevices(int $shipId): void
213
    {
214
        foreach ($this->shipSystemRepository->getTrackingShipSystems($shipId) as $system) {
215
            $wrapper = $this->shipWrapperFactory->wrapShip($system->getShip());
216
217
            $this->shipSystemManager->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_TRACKER, true);
218
        }
219
    }
220
221
    private function leaveSomeIntactModules(ShipInterface $ship): void
222
    {
223
        if ($ship->isShuttle()) {
224
            return;
225
        }
226
227
        $intactModules = [];
228
229
        foreach ($ship->getSystems() as $system) {
230
            if (
231
                $system->getModule() !== null
232
                && $system->getStatus() == 100
233
            ) {
234
                $module = $system->getModule();
235
236
                if (!array_key_exists($module->getId(), $intactModules)) {
237
                    $intactModules[$module->getId()] = $module;
238
                }
239
            }
240
        }
241
242
        //leave 50% of all intact modules
243
        $leaveCount = (int) ceil(count($intactModules) / 2);
244
        for ($i = 1; $i <= $leaveCount; $i++) {
245
            $module = $intactModules[array_rand($intactModules)];
246
            unset($intactModules[$module->getId()]);
247
248
            $this->shipStorageManager->upperStorage(
249
                $ship,
250
                $module->getCommodity(),
251
                1
252
            );
253
        }
254
    }
255
256
    private function orphanizeStorage(ShipInterface $ship): void
257
    {
258
        foreach ($ship->getStorage() as $storage) {
259
            $storage->setUser($this->userRepository->getFallbackUser());
260
            $this->storageRepository->save($storage);
261
        }
262
    }
263
264
    private function destroyTradepost(TradePostInterface $tradePost): void
265
    {
266
        //salvage offers and storage
267
        $storages = $this->storageRepository->getByTradePost($tradePost->getId());
268
        foreach ($storages as $storage) {
269
            //only 50% off all storages
270
            if (random_int(0, 1) === 0) {
271
                $this->storageRepository->delete($storage);
272
                continue;
273
            }
274
275
            //only 0 to 50% of the specific amount
276
            $amount = (int)ceil($storage->getAmount() / 100 * random_int(0, 50));
277
278
            if ($amount === 0) {
279
                $this->storageRepository->delete($storage);
280
                continue;
281
            }
282
283
            //add to trumfield storage
284
            $this->shipStorageManager->upperStorage(
285
                $tradePost->getShip(),
286
                $storage->getCommodity(),
287
                $amount
288
            );
289
290
            $this->storageRepository->delete($storage);
291
        }
292
293
        //remove tradepost and cascading stuff
294
        $this->tradePostRepository->delete($tradePost);
295
    }
296
297
    public function remove(ShipInterface $ship, ?bool $truncateCrew = false): void
298
    {
299
        $this->leaveFleet->leaveFleet($ship);
300
301
        if ($ship->getState() === ShipStateEnum::SHIP_STATE_ASTRO_FINALIZING) {
302
            $this->astroEntryLib->cancelAstroFinalizing($ship);
303
        }
304
305
        $wrapper = $this->shipWrapperFactory->wrapShip($ship);
306
307
        //both sides have to be cleared, foreign key violation
308
        if ($ship->isTractoring()) {
309
            $this->shipSystemManager->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM, true);
310
        } else {
311
            $tractoringShipWrapper = $wrapper->getTractoringShipWrapper();
312
            if ($tractoringShipWrapper !== null) {
313
                $this->shipSystemManager->deactivate($tractoringShipWrapper, ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM, true);
314
            }
315
        }
316
317
        foreach ($ship->getStorage() as $item) {
318
            $this->storageRepository->delete($item);
319
        }
320
321
        foreach ($ship->getDockedShips() as $dockedShip) {
322
            $dockedShip->setDockedTo(null);
323
            $this->shipRepository->save($dockedShip);
324
        }
325
326
        // delete torpedo storage
327
        $this->clearTorpedo->clearTorpedoStorage($wrapper);
328
329
        if ($truncateCrew) {
330
            $crewArray = [];
331
            foreach ($ship->getCrewlist() as $shipCrew) {
332
                $crewArray[] = $shipCrew->getCrew();
333
            }
334
335
            $this->shipCrewRepository->truncateByShip($ship->getId());
336
337
            foreach ($crewArray as $crew) {
338
                $this->crewRepository->delete($crew);
339
            }
340
341
            $ship->getCrewlist()->clear();
342
        }
343
344
        // reset tracker devices
345
        $this->resetTrackerDevices($ship->getId());
346
347
        foreach ($ship->getSystems() as $shipSystem) {
348
            $this->shipSystemRepository->delete($shipSystem);
349
        }
350
351
        $this->shipRepository->delete($ship);
352
    }
353
}
354