Completed
Push — develop ( 5d5326...be0e9e )
by Christian
02:27
created

src/N98/Util/Console/Helper/ParameterHelper.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace N98\Util\Console\Helper;
4
5
use Exception;
6
use InvalidArgumentException;
7
use N98\Util\Validator\FakeMetadataFactory;
8
use RuntimeException;
9
use Symfony\Component\Console\Helper\Helper as AbstractHelper;
10
use Symfony\Component\Console\Helper\QuestionHelper;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Console\Question\ChoiceQuestion;
14
use Symfony\Component\Console\Question\Question;
15
use Symfony\Component\Validator\Constraints;
16
use Symfony\Component\Validator\ConstraintValidatorFactory;
17
18
/**
19
 * Helper to init some parameters
20
 *
21
 * @package N98\Util\Console\Helper
22
 */
23
class ParameterHelper extends AbstractHelper
24
{
25
    /**
26
     * @var \Symfony\Component\Validator\Validator\ValidatorInterface
27
     */
28
    protected $validator;
29
30
    /**
31
     * Returns the canonical name of this helper.
32
     *
33
     * @return string The canonical name
34
     *
35
     * @api
36
     */
37
    public function getName()
38
    {
39
        return 'parameter';
40
    }
41
42
    /**
43
     * @param InputInterface $input
44
     * @param OutputInterface $output
45
     * @param string $argumentName
46
     * @param bool $withDefaultStore [optional]
47
     *
48
     * @return mixed
49
     *
50
     * @throws InvalidArgumentException
51
     * @throws \Exception
52
     */
53
    public function askStore(
54
        InputInterface $input,
55
        OutputInterface $output,
56
        $argumentName = 'store',
57
        $withDefaultStore = false
58
    ) {
59
        /* @var $storeManager \Magento\Store\Model\StoreManagerInterface */
60
        $storeManager = $this->getHelperSet()
61
            ->getCommand()
62
            ->getApplication()
63
            ->getObjectManager()
64
            ->get('Magento\Store\Model\StoreManagerInterface');
65
66
        try {
67
            if ($input->getArgument($argumentName) === null) {
68
                throw new RuntimeException('No store given');
69
            }
70
            $store = $storeManager->getStore($input->getArgument($argumentName));
71
        } catch (Exception $e) {
72
            $stores = [];
73
            $questionHelper = [];
74
            $i = 0;
75
            foreach ($storeManager->getStores($withDefaultStore) as $store) {
76
                $stores[$i] = $store->getId();
77
                $choices[$i + 1] = sprintf(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$choices was never initialized. Although not strictly required by PHP, it is generally a good practice to add $choices = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
78
                    '<comment>' . $store->getCode() . ' - ' . $store->getName() . '</comment>'
79
                );
80
                $i++;
81
            }
82
83
            if (count($stores) > 1) {
84
                $questionHelper[] = '';
85
86
                $question = new ChoiceQuestion('Please select a store', $choices);
87
                $question->setValidator(
88
                    function ($typeInput) use ($stores) {
89
                        if (!isset($stores[$typeInput - 1])) {
90
                            throw new InvalidArgumentException('Invalid store');
91
                        }
92
93
                        return $stores[$typeInput - 1];
94
                    }
95
                );
96
97
                /** @var QuestionHelper $questionHelper */
98
                $questionHelper = $this->getHelperSet()->get('question');
99
                $storeId = $questionHelper->ask($input, $output, $question);
100
            } else {
101
                // only one store view available -> take it
102
                $storeId = $stores[0];
103
            }
104
105
            $store = $storeManager->getStore($storeId);
106
        }
107
108
        return $store;
109
    }
110
111
    /**
112
     * @param InputInterface $input
113
     * @param OutputInterface $output
114
     * @param string $argumentName
115
     *
116
     * @return mixed
117
     * @throws InvalidArgumentException
118
     * @throws RuntimeException
119
     * @throws \Magento\Framework\Exception\LocalizedException
120
     * @throws \Exception
121
     */
122
    public function askWebsite(InputInterface $input, OutputInterface $output, $argumentName = 'website')
123
    {
124
        /* @var $storeManager \Magento\Store\Model\StoreManagerInterface */
125
        $storeManager = $this->getHelperSet()
126
            ->getCommand()
127
            ->getApplication()
128
            ->getObjectManager()
129
            ->get('Magento\Store\Model\StoreManagerInterface');
130
131
        try {
132
            if ($input->getArgument($argumentName) === null) {
133
                throw new RuntimeException('No website given');
134
            }
135
            $website = $storeManager->getWebsite($input->getArgument($argumentName));
136
        } catch (Exception $e) {
137
            $i = 0;
138
            $websites = [];
139
            foreach ($storeManager->getWebsites() as $website) {
140
                $websites[$i] = $website->getId();
141
                $choices[$i + 1] = '<comment>' . $website->getCode() . ' - ' . $website->getName() . '</comment>';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$choices was never initialized. Although not strictly required by PHP, it is generally a good practice to add $choices = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
142
                $i++;
143
            }
144
145
            if (count($websites) === 1) {
146
                return $storeManager->getWebsite($websites[0]);
147
            }
148
149
            $question = new ChoiceQuestion('Please select a website', $choices);
150 View Code Duplication
            $question->setValidator(function ($typeInput) use ($websites) {
151
                if (!isset($websites[$typeInput - 1])) {
152
                    throw new InvalidArgumentException('Invalid store');
153
                }
154
155
                return $websites[$typeInput - 1];
156
            });
157
158
            /** @var QuestionHelper $questionHelper */
159
            $questionHelper = $this->getHelperSet()->get('question');
160
            $websiteId = $questionHelper->ask($input, $output, $question);
161
162
            $website = $storeManager->getWebsite($websiteId);
163
        }
164
165
        return $website;
166
    }
167
168
    /**
169
     * @param InputInterface $input
170
     * @param OutputInterface $output
171
     * @param string $argumentName
172
     *
173
     * @return string
174
     * @throws \Exception
175
     */
176
    public function askEmail(InputInterface $input, OutputInterface $output, $argumentName = 'email')
177
    {
178
        $constraints = new Constraints\Collection(
179
            [
180
                'email' => [
181
                    new Constraints\NotBlank(),
182
                    new Constraints\Email(),
183
                ],
184
            ]
185
        );
186
187
        return $this->_validateArgument($input, $output, $argumentName, $input->getArgument($argumentName), $constraints);
188
    }
189
190
    /**
191
     * @param InputInterface $input
192
     * @param OutputInterface $output
193
     * @param string $argumentName
194
     * @return string
195
     * @throws \Exception
196
     */
197
    public function askPassword(
198
        InputInterface $input,
199
        OutputInterface $output,
200
        $argumentName = 'password',
201
        $needDigits = true
202
    ) {
203
        $validators = [];
204
205
        if ($needDigits) {
206
            $regex = [
207
                'pattern' => '/^(?=.*\d)(?=.*[a-zA-Z])/',
208
                'message' => 'Password must contain letters and at least one digit',
209
            ];
210
            $validators[] = new Constraints\Regex($regex);
211
        }
212
213
        $validators[] = new Constraints\Length(['min' => 6]);
214
215
        $constraints = new Constraints\Collection(
216
            [
217
                'password' => $validators,
218
            ]
219
        );
220
221
        return $this->_validateArgument($input, $output, $argumentName, $input->getArgument($argumentName), $constraints);
222
    }
223
224
    /**
225
     * @param InputInterface $input
226
     * @param OutputInterface $output
227
     * @param $name
228
     * @param $value
229
     * @param $constraints
230
     * @return mixed
231
     */
232
    protected function _validateArgument(InputInterface $input, OutputInterface $output, $name, $value, $constraints)
233
    {
234
        $validator = $this->initValidator();
235
        $errors = [];
236
237
        if (!empty($value)) {
238
            $errors = $validator->validate([$name => $value], $constraints);
239
            if (count($errors) > 0) {
240
                $output->writeln('<error>' . $errors[0]->getMessage() . '</error>');
241
            }
242
        }
243
244
        if (count($errors) > 0 || empty($value)) {
245
            $question = new Question('<question>' . ucfirst($name) . ': </question>');
246
            $question->setValidator(function ($typeInput) use ($validator, $constraints, $name) {
247
                $errors = $validator->validate([$name => $typeInput], $constraints);
248
                if (count($errors) > 0) {
249
                    throw new InvalidArgumentException($errors[0]->getMessage());
250
                }
251
252
                return $typeInput;
253
            });
254
255
            /** @var $questionHelper QuestionHelper */
256
            $questionHelper = $this->getHelperSet()->get('question');
257
            $value = $questionHelper->ask($input, $output, $question);
258
259
            return $value;
260
        }
261
        return $value;
262
    }
263
264
    /**
265
     * @return \Symfony\Component\Validator\Validator\ValidatorInterface
266
     */
267
    protected function initValidator()
268
    {
269
        if (null === $this->validator) {
270
            $this->validator = \Symfony\Component\Validator\Validation::createValidatorBuilder()
271
                ->setConstraintValidatorFactory(new ConstraintValidatorFactory())
272
                ->setMetadataFactory(new FakeMetadataFactory())
273
                ->getValidator();
274
        }
275
276
        return $this->validator;
277
    }
278
}
279