AddCommand::getAvailableLocales()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 0
1
<?php
2
/*
3
 * WellCommerce Open-Source E-Commerce Platform
4
 * 
5
 * This file is part of the WellCommerce package.
6
 *
7
 * (c) Adam Piotrowski <[email protected]>
8
 * 
9
 * For the full copyright and license information,
10
 * please view the LICENSE file that was distributed with this source code.
11
 */
12
13
namespace WellCommerce\Bundle\AppBundle\Command\Locale;
14
15
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Output\OutputInterface;
18
use Symfony\Component\Console\Question\ChoiceQuestion;
19
use Symfony\Component\Intl\Intl;
20
use WellCommerce\Bundle\AppBundle\DataSet\Admin\CurrencyDataSet;
21
use WellCommerce\Bundle\AppBundle\DataSet\Admin\LocaleDataSet;
22
use WellCommerce\Bundle\AppBundle\Entity\Currency;
23
use WellCommerce\Bundle\AppBundle\Entity\Locale;
24
use WellCommerce\Bundle\AppBundle\Service\Locale\Copier\LocaleCopierInterface;
25
use WellCommerce\Bundle\CoreBundle\Manager\ManagerInterface;
26
27
/**
28
 * Class AddLocaleCommand
29
 *
30
 * @author  Adam Piotrowski <[email protected]>
31
 */
32
final class AddCommand extends ContainerAwareCommand
33
{
34
    /**
35
     * @var ManagerInterface
36
     */
37
    protected $localeManager;
38
    
39
    /**
40
     * @var LocaleDataSet
41
     */
42
    protected $localeDataSet;
43
    
44
    /**
45
     * @var CurrencyDataSet
46
     */
47
    protected $currencyDataSet;
48
    
49
    /**
50
     * @var array
51
     */
52
    protected $installedLocales = [];
53
    
54
    /**
55
     * @var array
56
     */
57
    protected $installedCurrencies = [];
58
    
59
    /**
60
     * @var array
61
     */
62
    protected $availableLocales = [];
63
    
64
    protected function configure()
65
    {
66
        $this->setDescription('Adds a new locale and copies translatable entities');
67
        $this->setName('locale:add');
68
    }
69
    
70
    protected function initialize(InputInterface $input, OutputInterface $output)
71
    {
72
        $this->localeManager       = $this->getLocaleManager();
73
        $this->localeDataSet       = $this->getLocaleDataSet();
74
        $this->currencyDataSet     = $this->getCurrencyDataSet();
75
        $this->installedLocales    = $this->getInstalledLocales();
76
        $this->installedCurrencies = $this->getInstalledCurrencies();
77
        $this->availableLocales    = $this->getAvailableLocales();
78
    }
79
    
80
    protected function execute(InputInterface $input, OutputInterface $output)
81
    {
82
        $sourceLocale   = $this->chooseSourceLocale($input, $output);
83
        $targetLocale   = $this->chooseTargetLocale($input, $output);
84
        $targetCurrency = $this->chooseTargetCurrency($input, $output);
85
        
86
        $locale = $this->createLocale($targetLocale, $targetCurrency);
87
        $output->writeln(sprintf('<info>Created a new locale "%s"</info>', $locale->getCode()));
88
        
89
        $this->copyLocaleData($sourceLocale, $targetLocale);
90
        
91
        $output->writeln(sprintf('<info>Finished copying "%s" data</info>', $locale->getCode()));
92
    }
93
    
94
    private function createLocale(string $localeCode, string $targetLocaleCurrency): Locale
95
    {
96
        $currency = $this->getTargetCurrency($targetLocaleCurrency);
97
        /** @var Locale $locale */
98
        $locale = $this->localeManager->initResource();
99
        $locale->setCode($localeCode);
100
        $locale->setEnabled(true);
101
        $locale->setCurrency($currency);
102
        $this->localeManager->createResource($locale);
103
        
104
        return $locale;
105
    }
106
    
107
    private function findLocale(string $code): Locale
108
    {
109
        return $this->localeManager->getRepository()->findOneBy(['code' => $code]);
110
    }
111
    
112
    private function copyLocaleData(string $sourceLocaleCode, string $targetLocaleCode)
113
    {
114
        $sourceLocale = $this->findLocale($sourceLocaleCode);
115
        $targetLocale = $this->findLocale($targetLocaleCode);
116
        
117
        $this->getLocaleCopier()->copyLocaleData($sourceLocale, $targetLocale);
118
    }
119
    
120
    private function getTargetCurrency($targetCurrency): Currency
121
    {
122
        return $this->getContainer()->get('currency.repository')->findOneBy(['code' => $targetCurrency]);
123
    }
124
    
125
    private function chooseSourceLocale(InputInterface $input, OutputInterface $output): string
126
    {
127
        $defaultLocale = current($this->installedLocales);
128
        $question      = new ChoiceQuestion(
129
            sprintf(
130
                'Please select source locale from which new entities will be copied (defaults to "%s"):',
131
                $defaultLocale
132
            ),
133
            $this->installedLocales,
134
            $defaultLocale
135
        );
136
        
137
        $sourceLocale = $this->getHelper('question')->ask($input, $output, $question);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method ask() does only exist in the following implementations of said interface: Sensio\Bundle\GeneratorB...d\Helper\QuestionHelper, Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
138
        
139
        return $sourceLocale;
140
    }
141
    
142
    private function chooseTargetLocale(InputInterface $input, OutputInterface $output): string
143
    {
144
        $question     = new ChoiceQuestion('Please select target locale to which new entities will be copied:', $this->availableLocales);
145
        $targetLocale = $this->getHelper('question')->ask($input, $output, $question);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method ask() does only exist in the following implementations of said interface: Sensio\Bundle\GeneratorB...d\Helper\QuestionHelper, Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
146
        
147
        return $targetLocale;
148
    }
149
    
150
    private function chooseTargetCurrency(InputInterface $input, OutputInterface $output): string
151
    {
152
        $question             = new ChoiceQuestion('Please select a default currency for new locale:', $this->installedCurrencies);
153
        $targetLocaleCurrency = $this->getHelper('question')->ask($input, $output, $question);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method ask() does only exist in the following implementations of said interface: Sensio\Bundle\GeneratorB...d\Helper\QuestionHelper, Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
154
        
155
        return $targetLocaleCurrency;
156
    }
157
    
158
    private function getInstalledCurrencies(): array
159
    {
160
        return $this->currencyDataSet->getResult('select', ['order_by' => 'code'], [
161
            'label_column' => 'code',
162
            'value_column' => 'code',
163
        ]);
164
    }
165
    
166
    private function getInstalledLocales(): array
167
    {
168
        return $this->localeDataSet->getResult('select', ['order_by' => 'code'], [
169
            'label_column' => 'code',
170
            'value_column' => 'code',
171
        ]);
172
    }
173
    
174
    private function getAvailableLocales(): array
175
    {
176
        $locales    = [];
177
        $collection = Intl::getLocaleBundle()->getLocaleNames();
178
        
179
        foreach ($collection as $locale => $name) {
180
            if (!in_array($locale, $this->installedLocales)) {
181
                $locales[$locale] = $name;
182
            }
183
        }
184
        
185
        return $locales;
186
    }
187
    
188
    private function getLocaleDataSet(): LocaleDataSet
189
    {
190
        return $this->getContainer()->get('locale.dataset.admin');
191
    }
192
    
193
    private function getCurrencyDataSet(): CurrencyDataSet
194
    {
195
        return $this->getContainer()->get('currency.dataset.admin');
196
    }
197
    
198
    private function getLocaleManager(): ManagerInterface
199
    {
200
        return $this->getContainer()->get('locale.manager');
201
    }
202
    
203
    private function getLocaleCopier(): LocaleCopierInterface
204
    {
205
        return $this->getContainer()->get('locale.copier');
206
    }
207
}
208