1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the php-formatter package |
5
|
|
|
* |
6
|
|
|
* Copyright (c) 2014-2016 Marc Morera |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* Feel free to edit as you please, and have fun. |
12
|
|
|
* |
13
|
|
|
* @author Marc Morera <[email protected]> |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace Mmoreram\PHPFormatter\Command; |
17
|
|
|
|
18
|
|
|
use Exception; |
19
|
|
|
use IteratorAggregate; |
20
|
|
|
use Symfony\Component\Console\Command\Command; |
21
|
|
|
use Symfony\Component\Console\Input\InputArgument; |
22
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
23
|
|
|
use Symfony\Component\Console\Input\InputOption; |
24
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
25
|
|
|
use Symfony\Component\Filesystem\Filesystem; |
26
|
|
|
|
27
|
|
|
use Mmoreram\PHPFormatter\Finder\ConfigFinder; |
28
|
|
|
use Mmoreram\PHPFormatter\Finder\FileFinder; |
29
|
|
|
use Mmoreram\PHPFormatter\Loader\ConfigLoader; |
30
|
|
|
use Mmoreram\PHPFormatter\Sorter\UseSorter; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Class UseSortCommand. |
34
|
|
|
*/ |
35
|
|
|
class UseSortCommand extends Command |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* @var string |
39
|
|
|
* |
40
|
|
|
* Command name |
41
|
|
|
*/ |
42
|
|
|
const COMMAND_NAME = 'use-sort'; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* configure. |
46
|
|
|
*/ |
47
|
|
|
protected function configure() |
48
|
|
|
{ |
49
|
|
|
$this |
50
|
|
|
->setName('formatter:use:sort') |
51
|
|
|
->setDescription('Sort Use statements') |
52
|
|
|
->addArgument( |
53
|
|
|
'path', |
54
|
|
|
InputArgument::REQUIRED, |
55
|
|
|
'Path' |
56
|
|
|
) |
57
|
|
|
->addOption( |
58
|
|
|
'group', |
59
|
|
|
null, |
60
|
|
|
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, |
61
|
|
|
'Groups defined?' |
62
|
|
|
) |
63
|
|
|
->addOption( |
64
|
|
|
'sort-type', |
65
|
|
|
null, |
66
|
|
|
InputOption::VALUE_OPTIONAL, |
67
|
|
|
'Sort type' |
68
|
|
|
) |
69
|
|
|
->addOption( |
70
|
|
|
'sort-direction', |
71
|
|
|
null, |
72
|
|
|
InputOption::VALUE_OPTIONAL, |
73
|
|
|
'Sort direction' |
74
|
|
|
) |
75
|
|
|
->addOption( |
76
|
|
|
'group-type', |
77
|
|
|
null, |
78
|
|
|
InputOption::VALUE_OPTIONAL, |
79
|
|
|
'Type of grouping' |
80
|
|
|
) |
81
|
|
|
->addOption( |
82
|
|
|
'group-skip-empty', |
83
|
|
|
null, |
84
|
|
|
InputOption::VALUE_NONE, |
85
|
|
|
'Skip empty groups' |
86
|
|
|
) |
87
|
|
|
->addOption( |
88
|
|
|
'--config', |
89
|
|
|
'-c', |
90
|
|
|
InputOption::VALUE_OPTIONAL, |
91
|
|
|
'Config file directory', |
92
|
|
|
getcwd() |
93
|
|
|
) |
94
|
|
|
->addOption( |
95
|
|
|
'dry-run', |
96
|
|
|
null, |
97
|
|
|
InputOption::VALUE_NONE, |
98
|
|
|
'Just print the result, nothing is overwritten' |
99
|
|
|
); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Execute command. |
104
|
|
|
* |
105
|
|
|
* @param InputInterface $input Input |
106
|
|
|
* @param OutputInterface $output Output |
107
|
|
|
* |
108
|
|
|
* @return int|null|void |
109
|
|
|
* |
110
|
|
|
* @throws Exception |
111
|
|
|
*/ |
112
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
113
|
|
|
{ |
114
|
|
|
$path = $input->getArgument('path'); |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* We load the options to work with. |
118
|
|
|
*/ |
119
|
|
|
$options = $this->getUsableConfig($input); |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Building the real directory or file to work in. |
123
|
|
|
*/ |
124
|
|
|
$filesystem = new Filesystem(); |
125
|
|
|
if (!$filesystem->isAbsolutePath($path)) { |
126
|
|
|
$path = getcwd() . DIRECTORY_SEPARATOR . $path; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
View Code Duplication |
if (!is_file($path) && !is_dir($path)) { |
|
|
|
|
130
|
|
|
throw new Exception('Directory or file "' . $path . '" does not exist'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/* |
134
|
|
|
* Print dry-run message if needed |
135
|
|
|
*/ |
136
|
|
|
$this->printDryRunMessage( |
137
|
|
|
$input, |
138
|
|
|
$output, |
139
|
|
|
$path |
140
|
|
|
); |
141
|
|
|
|
142
|
|
|
/* |
143
|
|
|
* Print all configuration block if verbose level allows it |
144
|
|
|
*/ |
145
|
|
|
$this->printConfigUsed( |
146
|
|
|
$output, |
147
|
|
|
$options |
148
|
|
|
); |
149
|
|
|
|
150
|
|
|
$fileFinder = new FileFinder(); |
151
|
|
|
$files = $fileFinder->findPHPFilesByPath($path); |
152
|
|
|
|
153
|
|
|
/* |
154
|
|
|
* Parse and fix all found files |
155
|
|
|
*/ |
156
|
|
|
$this->parseAndFixFiles( |
157
|
|
|
$input, |
158
|
|
|
$output, |
159
|
|
|
$files, |
160
|
|
|
$options |
161
|
|
|
); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Load config. |
166
|
|
|
* |
167
|
|
|
* @param InputInterface $input Input |
168
|
|
|
* |
169
|
|
|
* @return array Config array |
170
|
|
|
*/ |
171
|
|
|
private function getUsableConfig(InputInterface $input) |
172
|
|
|
{ |
173
|
|
|
$configLoader = new ConfigLoader(); |
174
|
|
|
$configFinder = new ConfigFinder(); |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* This section is just for finding the right values to work with in |
178
|
|
|
* this execution. |
179
|
|
|
* |
180
|
|
|
* $options array will have, after this block, all these values |
181
|
|
|
*/ |
182
|
|
|
$configPath = rtrim($input->getOption('config'), DIRECTORY_SEPARATOR); |
183
|
|
|
|
184
|
|
|
return $configLoader->loadConfigValues( |
185
|
|
|
self::COMMAND_NAME, |
186
|
|
|
$configFinder->findConfigFile($configPath), |
187
|
|
|
[ |
188
|
|
|
'group' => $input->getOption('group'), |
189
|
|
|
'group-type' => $input->getOption('group-type'), |
190
|
|
|
'group-skip-empty' => $input->getOption('group-skip-empty'), |
191
|
|
|
'sort-type' => $input->getOption('sort-type'), |
192
|
|
|
'sort-direction' => $input->getOption('sort-direction'), |
193
|
|
|
], |
194
|
|
|
[ |
195
|
|
|
'group' => ['_main'], |
196
|
|
|
'group-type' => UseSorter::GROUP_TYPE_EACH, |
197
|
|
|
'group-skip-empty' => false, |
198
|
|
|
'sort-type' => UseSorter::SORT_TYPE_ALPHABETIC, |
199
|
|
|
'sort-direction' => UseSorter::SORT_DIRECTION_ASC, |
200
|
|
|
] |
201
|
|
|
); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Print the Dry-run message if needed. |
206
|
|
|
* |
207
|
|
|
* @param InputInterface $input Input |
208
|
|
|
* @param OutputInterface $output Output |
209
|
|
|
* @param string $path Path |
210
|
|
|
* |
211
|
|
|
* @return UseSortCommand self Object |
212
|
|
|
*/ |
213
|
|
|
private function printDryRunMessage( |
214
|
|
|
InputInterface $input, |
215
|
|
|
OutputInterface $output, |
216
|
|
|
$path |
217
|
|
|
) { |
218
|
|
|
$dryRun = $input->getOption('dry-run'); |
219
|
|
|
$verbose = $output->getVerbosity(); |
220
|
|
|
|
221
|
|
|
/* |
222
|
|
|
* Dry-run message |
223
|
|
|
*/ |
224
|
|
|
if ($dryRun && $verbose >= OutputInterface::VERBOSITY_VERBOSE) { |
225
|
|
|
$output->writeln('# This process has been executed in mode dry-run'); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
if ($verbose >= OutputInterface::VERBOSITY_VERBOSE) { |
229
|
|
|
$output->writeln('# Executing process in ' . $path); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
return $this; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Print the configuration used by the command. |
237
|
|
|
* |
238
|
|
|
* @param OutputInterface $output Output |
239
|
|
|
* @param array $options Options used by the command |
240
|
|
|
* |
241
|
|
|
* @return UseSortCommand self Object |
242
|
|
|
*/ |
243
|
|
|
private function printConfigUsed( |
244
|
|
|
OutputInterface $output, |
245
|
|
|
array $options |
246
|
|
|
) { |
247
|
|
|
$verbose = $output->getVerbosity(); |
248
|
|
|
|
249
|
|
|
/* |
250
|
|
|
* If verbose level is higher or equal than -vv, we print the config |
251
|
|
|
* file data, if is not empty. |
252
|
|
|
*/ |
253
|
|
|
if ($verbose >= OutputInterface::VERBOSITY_VERBOSE) { |
254
|
|
|
$output->writeln('# Executing process with this configuration'); |
255
|
|
|
if (!empty($options['group'])) { |
256
|
|
|
foreach ($options['group'] as $group) { |
257
|
|
|
$output->writeln('# --group="' . $group . '"'); |
258
|
|
|
} |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
if (!empty($options['group-type'])) { |
262
|
|
|
$output->writeln('# --group-type="' . $options['group-type'] . '"'); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
if (!empty($options['group-skip-empty'])) { |
266
|
|
|
$output->writeln('# --group-skip-empty="' . $options['group-skip-empty'] . '"'); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
if (!empty($options['sort-type'])) { |
270
|
|
|
$output->writeln('# --sort-type="' . $options['sort-type'] . '"'); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
if (!empty($options['sort-direction'])) { |
274
|
|
|
$output->writeln('# --sort-direction="' . $options['sort-direction'] . '"'); |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
$output->writeln('#'); |
279
|
|
|
|
280
|
|
|
return $this; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Parse and fix all files found. |
285
|
|
|
* |
286
|
|
|
* @param InputInterface $input Input |
287
|
|
|
* @param OutputInterface $output Output |
288
|
|
|
* @param IteratorAggregate $files Files |
289
|
|
|
* @param array $options Options |
290
|
|
|
* |
291
|
|
|
* @return UseSortCommand self Object |
292
|
|
|
*/ |
293
|
|
|
private function parseAndFixFiles( |
294
|
|
|
InputInterface $input, |
295
|
|
|
OutputInterface $output, |
296
|
|
|
IteratorAggregate $files, |
297
|
|
|
array $options |
298
|
|
|
|
299
|
|
|
) { |
300
|
|
|
$dryRun = $input->getOption('dry-run'); |
301
|
|
|
$verbose = $output->getVerbosity(); |
302
|
|
|
$useSorter = $this->createUseSorter($options); |
303
|
|
|
|
304
|
|
|
/* |
305
|
|
|
* Each found php file is processed |
306
|
|
|
*/ |
307
|
|
View Code Duplication |
foreach ($files as $file) { |
|
|
|
|
308
|
|
|
$data = file_get_contents($file); |
309
|
|
|
$result = $useSorter->sort($data); |
310
|
|
|
|
311
|
|
|
if ($result === false || $data === $result) { |
312
|
|
|
continue; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
if ($verbose >= OutputInterface::VERBOSITY_NORMAL) { |
316
|
|
|
$output->writeln('# ' . $file); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
if (!$dryRun) { |
320
|
|
|
file_put_contents($file, $result); |
321
|
|
|
} |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
return $this; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* Create UseSorter Object given a configuration. |
329
|
|
|
* |
330
|
|
|
* @param array $options Options |
331
|
|
|
* |
332
|
|
|
* @return UseSorter Use sorter instance |
333
|
|
|
*/ |
334
|
|
|
private function createUseSorter(array $options) |
335
|
|
|
{ |
336
|
|
|
/** |
337
|
|
|
* Creates the new UseSorter file, given config values. |
338
|
|
|
*/ |
339
|
|
|
$useSorter = new UseSorter(); |
340
|
|
|
$useSorter |
341
|
|
|
->setGroups($options['group']) |
342
|
|
|
->setGroupType($options['group-type']) |
343
|
|
|
->setGroupSkipEmpty($options['group-skip-empty']) |
344
|
|
|
->setSortType($options['sort-type']) |
345
|
|
|
->setSortDirection($options['sort-direction']); |
346
|
|
|
|
347
|
|
|
return $useSorter; |
348
|
|
|
} |
349
|
|
|
} |
350
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.