Passed
Branch master (9bcc45)
by Janko
41:23
created

RefactorRunner::getBuildplansWithDuplicates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 0
dl 0
loc 18
ccs 0
cts 10
cp 0
crap 2
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Component\Refactor;
6
7
use Doctrine\ORM\EntityManagerInterface;
8
use Stu\Component\Ship\Buildplan\BuildplanSignatureCreationInterface;
9
use Stu\Module\Logging\LoggerUtilFactoryInterface;
10
use Stu\Module\Logging\LoggerUtilInterface;
11
use Stu\Orm\Entity\BuildplanModuleInterface;
12
use Stu\Orm\Entity\ShipBuildplan;
13
use Stu\Orm\Entity\ShipBuildplanInterface;
14
use Stu\Orm\Repository\ShipBuildplanRepositoryInterface;
15
use Stu\Orm\Repository\ShipRepositoryInterface;
16
17
final class RefactorRunner
18
{
19
    private LoggerUtilInterface $logger;
20
21
    public function __construct(
22
        private ShipBuildplanRepositoryInterface $shipBuildplanRepository,
23
        private BuildplanSignatureCreationInterface $buildplanSignatureCreation,
24
        private ShipRepositoryInterface $shipRepository,
25
        private EntityManagerInterface $entityManager,
26
        LoggerUtilFactoryInterface $loggerUtilFactory
27
    ) {
28
        $this->logger = $loggerUtilFactory->getLoggerUtil(true);
29
    }
30
31
    public function refactor(): void
32
    {
33
        $this->recalculateAllBuildplanSignatures();
34
        $this->entityManager->flush();
35
        $this->removeBuildplanDuplicates();
36
    }
37
38
    private function recalculateAllBuildplanSignatures(): void
39
    {
40
        foreach ($this->shipBuildplanRepository->findAll() as $buildplan) {
41
            $calculatedSignature = $this->calculateSignature($buildplan);
42
43
            $buildplan->setSignature($calculatedSignature);
44
            $this->shipBuildplanRepository->save($buildplan);
45
        }
46
    }
47
48
    private function removeBuildplanDuplicates(): void
49
    {
50
        $buildplanCount = 0;
51
        $shipCount = 0;
52
53
        /** @var null|ShipBuildplanInterface */
54
        $lastBuildplan = null;
55
        foreach ($this->getBuildplansWithDuplicates() as $buildplan) {
56
            $buildplanUser = $buildplan->getUser();
57
            $buildplanRump = $buildplan->getRump();
58
            $buildplanSignature = $buildplan->getSignature();
59
60
            if (
61
                $lastBuildplan === null
62
                || $buildplanUser !== $lastBuildplan->getUser()
0 ignored issues
show
Bug introduced by
The method getUser() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

62
                || $buildplanUser !== $lastBuildplan->/** @scrutinizer ignore-call */ getUser()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
63
                || $buildplanRump !== $lastBuildplan->getRump()
64
                || $buildplanSignature !== $lastBuildplan->getSignature()
65
            ) {
66
                $lastBuildplan = $buildplan;
67
            } else {
68
                $buildplanCount++;
69
                foreach ($buildplan->getShiplist() as $ship) {
70
                    $ship->setBuildplan($lastBuildplan);
71
                    $this->shipRepository->save($ship);
72
                    $shipCount++;
73
                }
74
75
                $buildplan->getShiplist()->clear();
76
                $this->shipBuildplanRepository->delete($buildplan);
77
            }
78
        }
79
80
        $this->logger->logf('removed %d buildplan duplicates (%d ships affected)', $buildplanCount, $shipCount);
81
    }
82
83
    private function calculateSignature(ShipBuildplanInterface $buildplan): string
84
    {
85
        $modules = $buildplan
86
            ->getModules()
87
            ->map(fn(BuildplanModuleInterface $buildplanModule) => $buildplanModule->getModule())
88
            ->toArray();
89
90
        $crewUsage = $buildplan->getUser()->isNpc() ? 0 : $buildplan->getCrew();
91
92
        $signature = $this->buildplanSignatureCreation->createSignature(
93
            $modules,
94
            $crewUsage
95
        );
96
97
        return $signature;
98
    }
99
100
    /** @return array<ShipBuildplanInterface> */
101
    private function getBuildplansWithDuplicates(): array
102
    {
103
        return $this->entityManager
104
            ->createQuery(
105
                sprintf(
106
                    'SELECT bp FROM %1$s bp
107
                    WHERE EXISTS (SELECT bp2
108
                                    FROM %1$s bp2
109
                                    WHERE bp.signature = bp2.signature
110
                                    AND bp.rump_id = bp2.rump_id
111
                                    AND bp.user_id = bp2.user_id
112
                                    AND bp.id != bp2.id)
113
                    AND bp.signature IS NOT NULL
114
                    ORDER BY bp.user_id ASC, bp.rump_id ASC, bp.signature ASC, bp.id ASC',
115
                    ShipBuildplan::class
116
                )
117
            )
118
            ->getResult();
119
    }
120
}
121