CKEditorInstallerCommand   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 318
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 148
c 1
b 0
f 0
dl 0
loc 318
ccs 0
cts 196
cp 0
rs 9.28
wmc 39

12 Methods

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