EuInstallCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 9
dl 0
loc 12
rs 10
c 0
b 0
f 0

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 Gewebe\SyliusVATPlugin\Command;
6
7
use Gewebe\SyliusVATPlugin\Vat\Rates\RatesInterface;
8
use Sylius\Component\Addressing\Factory\ZoneFactory;
9
use Sylius\Component\Addressing\Model\CountryInterface;
10
use Sylius\Component\Addressing\Model\ZoneInterface;
11
use Sylius\Component\Core\Model\Scope;
12
use Sylius\Component\Core\Model\TaxRateInterface;
13
use Sylius\Component\Resource\Factory\FactoryInterface;
14
use Sylius\Component\Resource\Repository\RepositoryInterface;
15
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputArgument;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
use Symfony\Component\Console\Output\OutputInterface;
21
22
/**
23
 * Install EU countries, zones and VAT rates to Sylius
24
 */
25
final class EuInstallCommand extends Command
26
{
27
    public function __construct(
28
        private RatesInterface $vatRates,
29
        private FactoryInterface $countryFactory,
30
        private RepositoryInterface $countryRepository,
31
        private ZoneFactory $zoneFactory,
32
        private RepositoryInterface $zoneRepository,
33
        private FactoryInterface $taxRateFactory,
34
        private RepositoryInterface $taxRateRepository,
35
        private FactoryInterface $taxCategoryFactory,
36
        private RepositoryInterface $taxCategoryRepository,
37
    ) {
38
        parent::__construct();
39
    }
40
41
    protected function configure(): void
42
    {
43
        $this
44
            ->setName('vat:install:eu')
45
            ->setDescription('Install European countries, zones and VAT rates')
46
            ->addArgument(
47
                'country',
48
                InputArgument::OPTIONAL,
49
                'Domestic Country',
50
            )
51
            ->addOption(
52
                'categories',
53
                'c',
54
                InputOption::VALUE_REQUIRED,
55
                'Tax categories, e.g.: standard,reduced',
56
                'standard',
57
            )
58
            ->addOption(
59
                'included',
60
                'i',
61
                InputOption::VALUE_NONE,
62
                'Tax rate is included in price',
63
            )
64
            ->addOption(
65
                'threshold',
66
                't',
67
                InputOption::VALUE_REQUIRED,
68
                'Threshold Countries',
69
                '',
70
            )
71
        ;
72
    }
73
74
    private function getArgumentCountry(InputInterface $input): string
75
    {
76
        /** @var string $country */
77
        $country = $input->getArgument('country') ?? '';
78
79
        return strtolower($country);
80
    }
81
82
    /**
83
     * @return string[]
84
     */
85
    private function getOptionCategories(InputInterface $input): array
86
    {
87
        /** @var string $categories */
88
        $categories = $input->getOption('categories') ?? '';
89
90
        return explode(',', $categories);
91
    }
92
93
    private function getOptionIncluded(InputInterface $input): bool
94
    {
95
        return $input->getOption('included') === true;
96
    }
97
98
    private function getOptionThreshold(InputInterface $input): array
99
    {
100
        /** @var string $threshold */
101
        $threshold = $input->getOption('threshold') ?? '';
102
103
        return explode(',', strtolower($threshold));
104
    }
105
106
    protected function execute(InputInterface $input, OutputInterface $output): int
107
    {
108
        $baseCountry = $this->getArgumentCountry($input);
109
110
        $thresholdCountries = $this->getOptionThreshold($input);
111
112
        $taxCategories = $this->getOptionCategories($input);
113
        foreach ($taxCategories as $taxCategory) {
114
            $this->addTaxCategory($taxCategory);
115
        }
116
117
        $euZones = [];
118
        foreach ($this->vatRates->getCountries() as $countryCode => $countryName) {
119
            $output->writeln('Install: ' . $countryCode);
120
121
            $country = $this->addCountry(strtoupper($countryCode));
122
123
            $zone = $this->addZone(
124
                strtoupper($countryCode) . '-vat',
125
                $countryName . ' VAT',
126
                [$country->getCode()],
127
                ZoneInterface::TYPE_COUNTRY,
128
            );
129
130
            $euZones[] = $zone->getCode();
131
132
            if (in_array(strtolower($countryCode), $thresholdCountries, true)) {
133
                $zone = $this->addZone(
134
                    $countryCode . '-tax',
135
                    $countryName . ' Tax',
136
                    [$country->getCode()],
137
                    ZoneInterface::TYPE_COUNTRY,
138
                    Scope::TAX,
139
                );
140
            } elseif (strlen($baseCountry) > 0) {
141
                continue;
142
            }
143
144
            foreach ($taxCategories as $taxCategory) {
145
                $this->addTaxRate(
146
                    $countryCode,
147
                    $countryCode,
148
                    $taxCategory,
149
                    $zone,
150
                    $this->getOptionIncluded($input),
151
                );
152
            }
153
        }
154
155
        $output->writeln('Install: EU');
156
        $zone = $this->addZone(
157
            'EU',
158
            'European Union VAT',
159
            $euZones,
160
            ZoneInterface::TYPE_ZONE,
161
        );
162
163
        if (strlen($baseCountry) > 0) {
164
            foreach ($taxCategories as $taxCategory) {
165
                $this->addTaxRate(
166
                    $baseCountry,
167
                    'eu',
168
                    $taxCategory,
169
                    $zone,
170
                    $this->getOptionIncluded($input),
171
                );
172
            }
173
        }
174
175
        return 0;
176
    }
177
178
    private function addCountry(string $code): CountryInterface
179
    {
180
        /** @var CountryInterface|null $country */
181
        $country = $this->countryRepository->findOneBy(['code' => $code]);
182
        if ($country instanceof CountryInterface) {
183
            return $country;
184
        }
185
186
        /** @var CountryInterface $country */
187
        $country = $this->countryFactory->createNew();
188
        $country->setCode($code);
189
190
        $this->countryRepository->add($country);
191
192
        return $country;
193
    }
194
195
    private function addZone(string $code, string $name, array $countries, string $type, string $scope = Scope::ALL): ZoneInterface
196
    {
197
        /** @var ZoneInterface|null $zone */
198
        $zone = $this->zoneRepository->findOneBy(['code' => $code, 'type' => $type]);
199
        if ($zone instanceof ZoneInterface) {
200
            return $zone;
201
        }
202
203
        $zone = $this->zoneFactory->createWithMembers($countries);
204
        $zone->setCode($code);
205
        $zone->setName($name);
206
        $zone->setType($type);
207
        $zone->setScope($scope);
208
209
        $this->zoneRepository->add($zone);
210
211
        return $zone;
212
    }
213
214
    private function addTaxCategory(string $name): TaxCategoryInterface
215
    {
216
        /** @var TaxCategoryInterface|null $taxCategory */
217
        $taxCategory = $this->taxCategoryRepository->findOneBy(['code' => strtolower($name)]);
218
        if ($taxCategory instanceof TaxCategoryInterface) {
219
            return $taxCategory;
220
        }
221
222
        /** @var TaxCategoryInterface $taxCategory */
223
        $taxCategory = $this->taxCategoryFactory->createNew();
224
        $taxCategory->setCode(strtolower($name));
225
        $taxCategory->setName(ucfirst($name));
226
227
        $this->taxCategoryRepository->add($taxCategory);
228
229
        return $taxCategory;
230
    }
231
232
    private function addTaxRate(
233
        string $country,
234
        string $code,
235
        string $category,
236
        ZoneInterface $zone,
237
        bool $includedInPrice = false,
238
    ): void {
239
        try {
240
            $countryRate = $this->vatRates->getCountryRate(strtoupper($country), $category) / 100;
241
        } catch (\Exception $e) {
242
            return;
243
        }
244
245
        /** @var TaxRateInterface|null $taxRate */
246
        $taxRate = $this->taxRateRepository->findOneBy(['code' => strtolower($code) . '-' . $category]);
247
        if ($taxRate instanceof TaxRateInterface) {
248
            if ($taxRate->getAmount() !== $countryRate) {
249
                $taxRate->setAmount($countryRate);
250
251
                $this->taxRateRepository->add($taxRate);
252
            }
253
254
            return;
255
        }
256
257
        /** @var TaxCategoryInterface $taxCategory */
258
        $taxCategory = $this->taxCategoryRepository->findOneBy(['code' => $category]);
259
260
        /** @var TaxRateInterface $taxRate */
261
        $taxRate = $this->taxRateFactory->createNew();
262
        $taxRate->setCode(strtolower($code . '-' . $category));
263
        $taxRate->setName('VAT');
264
        $taxRate->setAmount($countryRate);
265
        $taxRate->setCalculator('default');
266
        $taxRate->setIncludedInPrice($includedInPrice);
267
        $taxRate->setZone($zone);
268
        $taxRate->setCategory($taxCategory);
269
270
        $this->taxRateRepository->add($taxRate);
271
    }
272
}
273