Completed
Pull Request — master (#40)
by Marko
116:46 queued 51:48
created

CKEditorInstallerCommand::createNotifier()   D

Complexity

Conditions 16
Paths 1

Size

Total Lines 85
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 85
rs 4.8736
c 0
b 0
f 0
cc 16
eloc 59
nc 1
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Ivory CKEditor package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\CKEditorBundle\Command;
13
14
use FOS\CKEditorBundle\Installer\CKEditorInstaller;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Helper\ProgressBar;
17
use Symfony\Component\Console\Helper\ProgressHelper;
18
use Symfony\Component\Console\Helper\QuestionHelper;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Question\ChoiceQuestion;
24
25
/**
26
 * @author GeLo <[email protected]>
27
 */
28
class CKEditorInstallerCommand extends Command
29
{
30
    /**
31
     * @var CKEditorInstaller
32
     */
33
    private $installer;
34
35
    /**
36
     * @param CKEditorInstaller|null $installer
37
     */
38
    public function __construct(CKEditorInstaller $installer = null)
39
    {
40
        parent::__construct();
41
42
        $this->installer = $installer ?: new CKEditorInstaller();
43
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48
    protected function configure()
49
    {
50
        $this
51
            ->setName('ckeditor:install')
52
            ->setDescription('Install CKEditor')
53
            ->addArgument('path', InputArgument::OPTIONAL, 'Where to install CKEditor')
54
            ->addOption('release', null, InputOption::VALUE_OPTIONAL, 'CKEditor release (basic, standard or full)')
55
            ->addOption('tag', null, InputOption::VALUE_OPTIONAL, 'CKEditor tag (x.y.z or latest)')
56
            ->addOption(
57
                'clear',
58
                null,
59
                InputOption::VALUE_OPTIONAL,
60
                'How to clear previous CKEditor installation (drop, keep or skip)'
61
            )
62
            ->addOption(
63
                'exclude',
64
                null,
65
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
66
                'Path to exclude when extracting CKEditor'
67
            )
68
            ->setHelp(
69
                <<<'EOF'
70
The <info>%command.name%</info> command install CKEditor in your application:
71
72
  <info>php %command.full_name%</info>
73
  
74
You can install it at a specific path (absolute):
75
76
  <info>php %command.full_name% path</info>
77
  
78
You can install a specific release (basic, standard or full):
79
80
  <info>php %command.full_name% --release=full</info>
81
  
82
You can install a specific version:
83
84
  <info>php %command.full_name% --tag=4.7.0</info>
85
86
If there is a previous CKEditor installation detected, 
87
you can control how it should be handled in non-interactive mode:
88
89
  <info>php %command.full_name% --clear=drop</info>
90
  <info>php %command.full_name% --clear=keep</info>
91
  <info>php %command.full_name% --clear=skip</info>
92
  
93
You can exclude path(s) when extracting CKEditor:
94
95
  <info>php %command.full_name% --exclude=samples --exclude=adapters</info>
96
EOF
97
            );
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    protected function execute(InputInterface $input, OutputInterface $output)
104
    {
105
        $this->title($output);
106
107
        $success = $this->installer->install($this->createOptions($input, $output));
108
109
        if ($success) {
110
            $this->success('CKEditor has been successfully installed...', $output);
111
        } else {
112
            $this->info('CKEditor installation has been skipped...', $output);
113
        }
114
    }
115
116
    /**
117
     * @param InputInterface  $input
118
     * @param OutputInterface $output
119
     *
120
     * @return mixed[]
121
     */
122
    private function createOptions(InputInterface $input, OutputInterface $output)
123
    {
124
        $options = ['notifier' => $this->createNotifier($input, $output)];
125
126
        if ($input->hasArgument('path')) {
127
            $options['path'] = $input->getArgument('path');
128
        }
129
130
        if ($input->hasOption('release')) {
131
            $options['release'] = $input->getOption('release');
132
        }
133
134
        if ($input->hasOption('tag')) {
135
            $options['version'] = $input->getOption('tag');
136
        }
137
138
        if ($input->hasOption('exclude')) {
139
            $options['excludes'] = $input->getOption('exclude');
140
        }
141
142
        if ($input->hasOption('clear')) {
143
            $options['clear'] = $input->getOption('clear');
144
        }
145
146
        return array_filter($options);
147
    }
148
149
    /**
150
     * @param InputInterface  $input
151
     * @param OutputInterface $output
152
     *
153
     * @return \Closure
154
     */
155
    private function createNotifier(InputInterface $input, OutputInterface $output)
156
    {
157
        $clear = $this->createProgressBar($output);
158
        $download = $this->createProgressBar($output);
159
        $extract = $this->createProgressBar($output);
160
161
        return function ($type, $data) use ($input, $output, $clear, $download, $extract) {
162
            switch ($type) {
163
                case CKEditorInstaller::NOTIFY_CLEAR:
164
                    $result = $this->choice(
165
                        [
166
                            sprintf('CKEditor is already installed in "%s"...', $data),
167
                            '',
168
                            'What do you want to do?',
169
                        ],
170
                        $choices = [
171
                            CKEditorInstaller::CLEAR_DROP => 'Drop the directory & reinstall CKEditor',
172
                            CKEditorInstaller::CLEAR_KEEP => 'Keep the directory & reinstall CKEditor by overriding files',
173
                            CKEditorInstaller::CLEAR_SKIP => 'Skip installation',
174
                        ],
175
                        CKEditorInstaller::CLEAR_DROP,
176
                        $input,
177
                        $output
178
                    );
179
180
                    if (($key = array_search($result, $choices, true)) !== false) {
181
                        $result = $key;
182
                    }
183
184
                    if ($result === CKEditorInstaller::CLEAR_DROP) {
185
                        $this->comment(sprintf('Dropping CKEditor from "%s"', $data), $output);
186
                    }
187
188
                    return $result;
189
190
                case CKEditorInstaller::NOTIFY_CLEAR_ARCHIVE:
191
                    $this->comment(sprintf('Dropping CKEditor ZIP archive "%s"', $data), $output);
192
                    break;
193
194
                case CKEditorInstaller::NOTIFY_CLEAR_COMPLETE:
195
                    $this->finishProgressBar($clear, $output);
196
                    break;
197
198
                case CKEditorInstaller::NOTIFY_CLEAR_PROGRESS:
199
                    $clear->advance();
200
                    break;
201
202
                case CKEditorInstaller::NOTIFY_CLEAR_SIZE:
203
                    $this->startProgressBar($clear, $output, $data);
204
                    break;
205
206
                case CKEditorInstaller::NOTIFY_DOWNLOAD:
207
                    $this->comment(sprintf('Downloading CKEditor ZIP archive from "%s"', $data), $output);
208
                    break;
209
210
                case CKEditorInstaller::NOTIFY_DOWNLOAD_COMPLETE:
211
                    $this->finishProgressBar($download, $output);
212
                    break;
213
214
                case CKEditorInstaller::NOTIFY_DOWNLOAD_PROGRESS:
215
                    $this->advanceProgressBar($download, $data);
216
                    break;
217
218
                case CKEditorInstaller::NOTIFY_DOWNLOAD_SIZE:
219
                    $this->startProgressBar($download, $output, $data);
220
                    break;
221
222
                case CKEditorInstaller::NOTIFY_EXTRACT:
223
                    $this->comment(sprintf('Extracting CKEditor ZIP archive to "%s"', $data), $output);
224
                    break;
225
226
                case CKEditorInstaller::NOTIFY_EXTRACT_COMPLETE:
227
                    $this->finishProgressBar($extract, $output);
228
                    break;
229
230
                case CKEditorInstaller::NOTIFY_EXTRACT_PROGRESS:
231
                    $extract->advance();
232
                    break;
233
234
                case CKEditorInstaller::NOTIFY_EXTRACT_SIZE:
235
                    $this->startProgressBar($extract, $output, $data);
236
                    break;
237
            }
238
        };
239
    }
240
241
    /**
242
     * @param OutputInterface $output
243
     */
244
    private function title(OutputInterface $output)
245
    {
246
        $output->writeln(
247
            [
248
                '----------------------',
249
                '| CKEditor Installer |',
250
                '----------------------',
251
                '',
252
            ]
253
        );
254
    }
255
256
    /**
257
     * @param string|string[] $message
258
     * @param OutputInterface $output
259
     */
260
    private function comment($message, OutputInterface $output)
261
    {
262
        $output->writeln(' // '.$message);
263
        $output->writeln('');
264
    }
265
266
    /**
267
     * @param string          $message
268
     * @param OutputInterface $output
269
     */
270
    private function success($message, OutputInterface $output)
271
    {
272
        $this->block('[OK] - '.$message, $output, 'green', 'black');
273
    }
274
275
    /**
276
     * @param string          $message
277
     * @param OutputInterface $output
278
     */
279
    private function info($message, OutputInterface $output)
280
    {
281
        $this->block('[INFO] - '.$message, $output, 'yellow', 'black');
282
    }
283
284
    /**
285
     * @param string          $message
286
     * @param OutputInterface $output
287
     * @param string          $background
288
     * @param string          $font
289
     */
290
    private function block($message, OutputInterface $output, $background = null, $font = null)
291
    {
292
        $options = [];
293
294
        if ($background !== null) {
295
            $options[] = 'bg='.$background;
296
        }
297
298
        if ($font !== null) {
299
            $options[] = 'fg='.$font;
300
        }
301
302
        $pattern = ' %s ';
303
304
        if (!empty($options)) {
305
            $pattern = '<'.implode(';', $options).'>'.$pattern.'</>';
306
        }
307
308
        $output->writeln($block = sprintf($pattern, str_repeat(' ', strlen($message))));
309
        $output->writeln(sprintf($pattern, $message));
310
        $output->writeln($block);
311
    }
312
313
    /**
314
     * @param string|string[] $question
315
     * @param string[]        $choices
316
     * @param string          $default
317
     * @param InputInterface  $input
318
     * @param OutputInterface $output
319
     *
320
     * @return string|null
321
     */
322
    private function choice($question, array $choices, $default, InputInterface $input, OutputInterface $output)
323
    {
324
        $helper = new QuestionHelper();
325
326
        if (is_array($question)) {
327
            $question = implode("\n", $question);
328
        }
329
330
        $result = $helper->ask(
331
            $input,
332
            $output,
333
            new ChoiceQuestion($question, $choices, $choices[$default])
334
        );
335
336
        $output->writeln('');
337
338
        return $result;
339
    }
340
341
    /**
342
     * @param OutputInterface $output
343
     *
344
     * @return ProgressBar|ProgressHelper
345
     */
346
    private function createProgressBar(OutputInterface $output)
347
    {
348
        return class_exists(ProgressBar::class) ? new ProgressBar($output) : new ProgressHelper();
349
    }
350
351
    /**
352
     * @param ProgressBar|ProgressHelper $progress
353
     * @param OutputInterface            $output
354
     * @param int|null                   $max
355
     */
356
    private function startProgressBar($progress, OutputInterface $output, $max = null)
357
    {
358
        class_exists(ProgressBar::class) ? $progress->start($max) : $progress->start($output, $max);
0 ignored issues
show
Documentation introduced by
$output is of type object<Symfony\Component...Output\OutputInterface>, but the function expects a null|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to ProgressBar::start() has too many arguments starting with $max.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
359
    }
360
361
    /**
362
     * @param ProgressBar|ProgressHelper $progress
363
     * @param int                        $current
364
     */
365
    private function advanceProgressBar($progress, $current)
366
    {
367
        class_exists(ProgressBar::class) ? $progress->setProgress($current) : $progress->setCurrent($current);
0 ignored issues
show
Bug introduced by
The method setCurrent() does not seem to exist on object<Symfony\Component...ole\Helper\ProgressBar>.

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...
368
    }
369
370
    /**
371
     * @param ProgressBar|ProgressHelper $progress
372
     * @param OutputInterface            $output
373
     */
374
    private function finishProgressBar($progress, OutputInterface $output)
375
    {
376
        $progress->finish();
377
        $output->writeln(['', '']);
378
    }
379
}
380