Completed
Push — master ( 754a73...5e8c03 )
by Maximilian
14:11
created

CKEditorInstallerCommand::info()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
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;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Helper\ProgressHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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) {
0 ignored issues
show
introduced by
The condition $success is always true.
Loading history...
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);
0 ignored issues
show
Bug introduced by
Are you sure $message of type string|string[] can be used in concatenation? ( Ignorable by Annotation )

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

262
        $output->writeln(' // './** @scrutinizer ignore-type */ $message);
Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type boolean which is incompatible with the documented return type null|string.
Loading history...
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
Unused Code introduced by
The call to Symfony\Component\Consol...er\ProgressBar::start() has too many arguments starting with $max. ( Ignorable by Annotation )

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

358
        class_exists(ProgressBar::class) ? $progress->start($max) : $progress->/** @scrutinizer ignore-call */ start($output, $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. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
$output of type Symfony\Component\Console\Output\OutputInterface is incompatible with the type null|integer expected by parameter $max of Symfony\Component\Consol...er\ProgressBar::start(). ( Ignorable by Annotation )

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

358
        class_exists(ProgressBar::class) ? $progress->start($max) : $progress->start(/** @scrutinizer ignore-type */ $output, $max);
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 exist on Symfony\Component\Console\Helper\ProgressBar. ( Ignorable by Annotation )

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

367
        class_exists(ProgressBar::class) ? $progress->setProgress($current) : $progress->/** @scrutinizer ignore-call */ setCurrent($current);

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