These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Rj\FrontendBundle\Command; |
||
4 | |||
5 | use Rj\FrontendBundle\Command\Options\SimpleOptionHelper; |
||
6 | use Rj\FrontendBundle\Command\Options\ChoiceOptionHelper; |
||
7 | use Symfony\Component\Console\Command\Command; |
||
8 | use Symfony\Component\Console\Input\ArrayInput; |
||
9 | use Symfony\Component\Console\Input\InputInterface; |
||
10 | use Symfony\Component\Console\Input\InputOption; |
||
11 | use Symfony\Component\Console\Output\OutputInterface; |
||
12 | use Symfony\Component\Templating\PhpEngine; |
||
13 | use Symfony\Component\Templating\TemplateNameParser; |
||
14 | use Symfony\Component\Templating\Loader\FilesystemLoader; |
||
15 | |||
16 | class SetupCommand extends Command |
||
17 | { |
||
18 | private $templating; |
||
19 | private $rootDir = null; |
||
20 | |||
21 | 30 | public function __construct($name = null) |
|
22 | { |
||
23 | 30 | parent::__construct($name); |
|
24 | |||
25 | 30 | $this->templating = new PhpEngine( |
|
26 | 30 | new TemplateNameParser(), |
|
27 | 30 | new FilesystemLoader(array(__DIR__.'/../Resources/blueprints/%name%')) |
|
28 | ); |
||
29 | 30 | } |
|
30 | |||
31 | 30 | public function setRootDir($path) |
|
32 | { |
||
33 | 30 | $this->rootDir = $path; |
|
34 | 30 | } |
|
35 | |||
36 | 30 | protected function configure() |
|
37 | { |
||
38 | $this |
||
39 | 30 | ->setName('rj_frontend:setup') |
|
40 | 30 | ->setDescription('Generate the configuration for the asset pipeline') |
|
41 | 30 | ->addOption( |
|
42 | 30 | 'dry-run', |
|
43 | 30 | null, |
|
44 | 30 | InputOption::VALUE_NONE, |
|
45 | 30 | 'Output which commands would have been run instead of running them' |
|
46 | ) |
||
47 | 30 | ->addOption( |
|
48 | 30 | 'force', |
|
49 | 30 | null, |
|
50 | 30 | InputOption::VALUE_NONE, |
|
51 | 30 | 'Force execution' |
|
52 | ) |
||
53 | 30 | ->addOption( |
|
54 | 30 | 'src-dir', |
|
55 | 30 | null, |
|
56 | 30 | InputOption::VALUE_REQUIRED, |
|
57 | 30 | 'Path to the directory containing the source assets [e.g. '.$this->getDefaultOption('src-dir').']' |
|
58 | ) |
||
59 | 30 | ->addOption( |
|
60 | 30 | 'dest-dir', |
|
61 | 30 | null, |
|
62 | 30 | InputOption::VALUE_REQUIRED, |
|
63 | 30 | 'Path to the directory containing the compiled assets [e.g. '.$this->getDefaultOption('dest-dir').']' |
|
64 | ) |
||
65 | 30 | ->addOption( |
|
66 | 30 | 'pipeline', |
|
67 | 30 | null, |
|
68 | 30 | InputOption::VALUE_REQUIRED, |
|
69 | 30 | 'Asset pipeline to use [only gulp is available at the moment]' |
|
70 | ) |
||
71 | 30 | ->addOption( |
|
72 | 30 | 'csspre', |
|
73 | 30 | null, |
|
74 | 30 | InputOption::VALUE_REQUIRED, |
|
75 | 30 | 'CSS preprocessor to use [sass, less or none]' |
|
76 | ) |
||
77 | 30 | ->addOption( |
|
78 | 30 | 'coffee', |
|
79 | 30 | null, |
|
80 | 30 | InputOption::VALUE_REQUIRED, |
|
81 | 30 | 'Use the CoffeeScript compiler [true or false]' |
|
82 | ) |
||
83 | ; |
||
84 | 30 | } |
|
85 | |||
86 | 4 | protected function interact(InputInterface $input, OutputInterface $output) |
|
87 | { |
||
88 | 4 | $simpleOptionHelper = new SimpleOptionHelper($this, $input, $output); |
|
89 | 4 | $choiceOptionHelper = new ChoiceOptionHelper($this, $input, $output); |
|
90 | |||
91 | $simpleOptionHelper |
||
92 | 4 | ->setDefaultValue($this->getDefaultOption('src-dir')) |
|
93 | 4 | ->setOption( |
|
94 | 4 | 'src-dir', |
|
95 | 4 | 'Path to the directory containing the source assets [default is '.$this->getDefaultOption('src-dir').']' |
|
96 | ) |
||
97 | ; |
||
98 | |||
99 | $simpleOptionHelper |
||
100 | 4 | ->setDefaultValue($this->getDefaultOption('dest-dir')) |
|
101 | 4 | ->setOption( |
|
102 | 4 | 'dest-dir', |
|
103 | 4 | 'Path to the directory containing the compiled assets [default is '.$this->getDefaultOption('dest-dir').']' |
|
104 | ) |
||
105 | ; |
||
106 | |||
107 | $choiceOptionHelper |
||
108 | 4 | ->setAllowedValues(array('gulp')) |
|
109 | 4 | ->setErrorMessage('%s is not a supported asset pipeline') |
|
110 | 4 | ->setOption( |
|
111 | 4 | 'pipeline', |
|
112 | 4 | 'Asset pipeline to use [only gulp is available at the moment]' |
|
113 | ) |
||
114 | ; |
||
115 | |||
116 | $choiceOptionHelper |
||
117 | 4 | ->setAllowedValues(array('sass', 'less', 'none')) |
|
118 | 4 | ->setErrorMessage('%s is not a supported CSS preprocessor') |
|
119 | 4 | ->setOption( |
|
120 | 4 | 'csspre', |
|
121 | 4 | 'CSS preprocessor to use [default is '.$this->getDefaultOption('csspre').']' |
|
122 | ) |
||
123 | ; |
||
124 | |||
125 | $choiceOptionHelper |
||
126 | 4 | ->setAllowedValues(array('false', 'true')) |
|
127 | 4 | ->setErrorMessage('%s is not a supported value for --coffee. Use either true or false') |
|
128 | 4 | ->setOption( |
|
129 | 4 | 'coffee', |
|
130 | 4 | 'Whether to use the CoffeeScript compiler [default is '.$this->getDefaultOption('coffee').']' |
|
131 | ) |
||
132 | ; |
||
133 | |||
134 | 4 | $output->writeln(''); |
|
135 | 4 | } |
|
136 | |||
137 | 30 | protected function execute(InputInterface $input, OutputInterface $output) |
|
138 | { |
||
139 | 30 | $this->processOptions($input); |
|
140 | |||
141 | 30 | $output->writeln('<info>Selected options are:</info>'); |
|
142 | 30 | $output->writeln('src-dir: '.$input->getOption('src-dir')); |
|
143 | 30 | $output->writeln('dest-dir: '.$input->getOption('dest-dir')); |
|
144 | 30 | $output->writeln('pipeline: '.$input->getOption('pipeline')); |
|
145 | 30 | $output->writeln('csspre: '.$input->getOption('csspre')); |
|
146 | 30 | $output->writeln('coffee: '.($input->getOption('coffee') ? 'true' : 'false')); |
|
147 | |||
148 | 30 | if (!preg_match('|web/.+|', $input->getOption('dest-dir'))) { |
|
149 | 6 | throw new \InvalidArgumentException("'dest-dir' must be a directory under web/"); |
|
150 | } |
||
151 | |||
152 | 24 | $output->writeln(''); |
|
153 | 24 | $this->createSourceTree($input, $output); |
|
154 | 24 | $this->createBuildFile($input, $output); |
|
155 | 24 | $this->createPackageJson($input, $output); |
|
156 | 24 | $this->createBowerJson($input, $output); |
|
157 | |||
158 | 24 | $output->writeln(''); |
|
159 | 24 | $this->runInstallCommand($input, $output); |
|
160 | 24 | } |
|
161 | |||
162 | 24 | private function runInstallCommand($input, $output) |
|
163 | { |
||
164 | 24 | if ($input->getOption('dry-run')) { |
|
165 | 12 | return $output->writeln('<info>Would have installed npm and bower dependencies</info>'); |
|
166 | } |
||
167 | |||
168 | 12 | $this->getApplication()->find('rj_frontend:install') |
|
169 | 12 | ->run(new ArrayInput(array('command' => 'rj_frontend:install')), $output); |
|
170 | 12 | } |
|
171 | |||
172 | 24 | private function createSourceTree($input, $output) |
|
173 | { |
||
174 | 24 | $blueprints = __DIR__.'/../Resources/blueprints'; |
|
175 | 24 | $dryRun = $input->getOption('dry-run'); |
|
176 | 24 | $base = $input->getOption('src-dir'); |
|
177 | |||
178 | 24 | $output->writeln($dryRun |
|
179 | 12 | ? '<info>Would have created directory tree for source assets:</info>' |
|
180 | 24 | : '<info>Creating directory tree for source assets:</info>' |
|
181 | ); |
||
182 | |||
183 | 24 | $blueprintDir = "$blueprints/images"; |
|
184 | 24 | $this->createDirFromBlueprint($input, $output, $blueprintDir, "$base/images"); |
|
185 | |||
186 | 24 | $blueprintDir = "$blueprints/stylesheets/".$input->getOption('csspre'); |
|
187 | 24 | $this->createDirFromBlueprint($input, $output, $blueprintDir, "$base/stylesheets"); |
|
188 | |||
189 | 24 | $blueprintDir = "$blueprints/scripts/"; |
|
190 | 24 | $blueprintDir .= $input->getOption('coffee') ? 'coffee' : 'js'; |
|
191 | 24 | $this->createDirFromBlueprint($input, $output, $blueprintDir, "$base/scripts"); |
|
192 | |||
193 | 24 | $output->writeln(''); |
|
194 | 24 | } |
|
195 | |||
196 | 24 | View Code Duplication | private function createBuildFile($input, $output) |
0 ignored issues
–
show
|
|||
197 | { |
||
198 | $files = array( |
||
199 | 24 | 'gulp' => 'gulp/gulpfile.js', |
|
200 | ); |
||
201 | |||
202 | 24 | $this->createFileFromTemplate($input, $output, 'pipelines/'.$files[$input->getOption('pipeline')]); |
|
203 | 24 | } |
|
204 | |||
205 | 24 | View Code Duplication | private function createPackageJson($input, $output) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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.
Loading history...
|
|||
206 | { |
||
207 | $files = array( |
||
208 | 24 | 'gulp' => 'gulp/package.json', |
|
209 | ); |
||
210 | |||
211 | 24 | $this->createFileFromTemplate($input, $output, 'pipelines/'.$files[$input->getOption('pipeline')]); |
|
212 | 24 | } |
|
213 | |||
214 | 24 | private function createBowerJson($input, $output) |
|
215 | { |
||
216 | 24 | $this->createFileFromTemplate($input, $output, 'bower.json'); |
|
217 | 24 | } |
|
218 | |||
219 | 24 | private function createDirFromBlueprint($input, $output, $blueprintDir, $targetDir) |
|
220 | { |
||
221 | 24 | $dryRun = $input->getOption('dry-run'); |
|
222 | |||
223 | 24 | if (!$dryRun && !file_exists($targetDir)) { |
|
224 | 12 | mkdir($targetDir, 0777, true); |
|
225 | } |
||
226 | |||
227 | 24 | foreach (preg_grep('/^\.?\w+/', scandir($blueprintDir)) as $entry) { |
|
228 | 24 | $target = $entry; |
|
229 | |||
230 | 24 | $isPhpTemplate = substr($entry, strrpos($entry, '.')) === '.php'; |
|
231 | 24 | if ($isPhpTemplate) { |
|
232 | 24 | $entry = str_replace('.php', '', $entry); |
|
233 | 24 | $target = str_replace('.php', '', $target); |
|
234 | } |
||
235 | |||
236 | 24 | $entry = $blueprintDir.'/'.$entry; |
|
237 | 24 | $target = $targetDir.'/'.$target; |
|
238 | |||
239 | 24 | if (!$dryRun) { |
|
240 | 12 | if ($isPhpTemplate) { |
|
241 | 12 | $this->renderTemplate($input, $output, $entry, $target); |
|
242 | } else { |
||
243 | 12 | if (file_exists($target) && !$input->getOption('force')) { |
|
244 | $output->writeln( |
||
245 | "<error>$target already exists. Run this command with --force to overwrite</error> |
||
246 | "); |
||
247 | |||
248 | continue; |
||
249 | } |
||
250 | |||
251 | 12 | copy($entry, $target); |
|
252 | } |
||
253 | } |
||
254 | |||
255 | 24 | $output->writeln($target); |
|
256 | } |
||
257 | 24 | } |
|
258 | |||
259 | 24 | private function createFileFromTemplate($input, $output, $file) |
|
260 | { |
||
261 | 24 | $dryRun = $input->getOption('dry-run'); |
|
262 | |||
263 | 24 | $targetFile = basename($file); |
|
264 | 24 | if (!empty($this->rootDir)) { |
|
265 | 24 | $targetFile = $this->rootDir.'/'.$targetFile; |
|
266 | } |
||
267 | |||
268 | 24 | $output->writeln($dryRun |
|
269 | 12 | ? "<info>Would have created file $targetFile</info>" |
|
270 | 24 | : "<info>Creating file $targetFile</info>" |
|
271 | ); |
||
272 | |||
273 | 24 | if ($dryRun) { |
|
274 | 12 | return; |
|
275 | } |
||
276 | |||
277 | 12 | $this->renderTemplate($input, $output, $file, $targetFile); |
|
278 | 12 | } |
|
279 | |||
280 | 12 | private function renderTemplate($input, $output, $file, $target) |
|
281 | { |
||
282 | 12 | if (file_exists($target) && !$input->getOption('force')) { |
|
283 | 2 | return $output->writeln( |
|
284 | "<error>$target already exists. Run this command with --force to overwrite</error> |
||
285 | 2 | "); |
|
286 | } |
||
287 | |||
288 | 12 | switch ($input->getOption('csspre')) { |
|
289 | case 'sass': |
||
290 | 10 | $stylesheetExtension = 'scss'; |
|
291 | 10 | break; |
|
292 | case 'less': |
||
293 | 2 | $stylesheetExtension = 'less'; |
|
294 | 2 | break; |
|
295 | default: |
||
296 | $stylesheetExtension = 'css'; |
||
297 | break; |
||
298 | } |
||
299 | |||
300 | 12 | file_put_contents($target, $this->templating->render("$file.php", array( |
|
301 | 12 | 'projectName' => basename(getcwd()), |
|
302 | 12 | 'srcDir' => $input->getOption('src-dir'), |
|
303 | 12 | 'destDir' => $input->getOption('dest-dir'), |
|
304 | 12 | 'prefix' => str_replace('web/', '', $input->getOption('dest-dir')), |
|
305 | 12 | 'coffee' => $input->getOption('coffee'), |
|
306 | 12 | 'cssPre' => $input->getOption('csspre'), |
|
307 | 12 | 'stylesheetExtension' => $stylesheetExtension, |
|
308 | ))); |
||
309 | 12 | } |
|
310 | |||
311 | 30 | private function processOptions($input) |
|
312 | { |
||
313 | 30 | foreach ($input->getOptions() as $name => $value) { |
|
314 | 30 | if (!$input->isInteractive() && $value === null) { |
|
315 | 26 | $value = $this->getDefaultOption($name); |
|
316 | } |
||
317 | |||
318 | 30 | if ($value === 'true') { |
|
319 | 4 | $value = true; |
|
320 | 30 | } elseif ($value === 'false') { |
|
321 | 24 | $value = false; |
|
322 | } |
||
323 | |||
324 | 30 | $input->setOption($name, $value); |
|
325 | } |
||
326 | 30 | } |
|
327 | |||
328 | 30 | private function getDefaultOption($name) |
|
329 | { |
||
330 | $defaults = array( |
||
331 | 30 | 'src-dir' => empty($this->rootDir) ? 'app/Resources' : $this->rootDir.'/app/Resources', |
|
332 | 30 | 'dest-dir' => empty($this->rootDir) ? 'web/assets' : $this->rootDir.'/web/assets', |
|
333 | 30 | 'pipeline' => 'gulp', |
|
334 | 30 | 'csspre' => 'sass', |
|
335 | 30 | 'coffee' => 'false', |
|
336 | ); |
||
337 | |||
338 | 30 | return $defaults[$name]; |
|
339 | } |
||
340 | } |
||
341 |
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.