Completed
Push — master ( b28d44...6f2c13 )
by Marko
40:03 queued 25:04
created

src/Command/CKEditorInstallerCommand.php (2 issues)

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