These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* |
||
6 | * This file is a part of Sculpin. |
||
7 | * |
||
8 | * (c) Dragonfly Development Inc. |
||
9 | * |
||
10 | * For the full copyright and license information, please view the LICENSE |
||
11 | * file that was distributed with this source code. |
||
12 | */ |
||
13 | |||
14 | namespace Sculpin\Bundle\SculpinBundle\Command; |
||
15 | |||
16 | use Sculpin\Bundle\SculpinBundle\Console\Application; |
||
17 | use Sculpin\Bundle\SculpinBundle\HttpServer\HttpServer; |
||
18 | use Sculpin\Core\Io\ConsoleIo; |
||
19 | use Sculpin\Core\Io\IoInterface; |
||
20 | use Sculpin\Core\Sculpin; |
||
21 | use Sculpin\Core\Source\DataSourceInterface; |
||
22 | use Sculpin\Core\Source\SourceSet; |
||
23 | use Symfony\Component\Console\Helper\QuestionHelper; |
||
24 | use Symfony\Component\Console\Input\InputInterface; |
||
25 | use Symfony\Component\Console\Input\InputOption; |
||
26 | use Symfony\Component\Console\Output\OutputInterface; |
||
27 | use Symfony\Component\Console\Question\ConfirmationQuestion; |
||
28 | use Symfony\Component\Filesystem\Exception\IOException; |
||
29 | use Twig\Error\LoaderError; |
||
30 | use Twig\Error\RuntimeError; |
||
31 | use Twig\Error\SyntaxError; |
||
32 | |||
33 | /** |
||
34 | * Generate the site. |
||
35 | * |
||
36 | * @author Beau Simensen <[email protected]> |
||
37 | */ |
||
38 | class GenerateCommand extends AbstractCommand |
||
39 | { |
||
40 | /** |
||
41 | * @var bool |
||
42 | */ |
||
43 | protected $throwExceptions; |
||
44 | |||
45 | /** |
||
46 | * {@inheritdoc} |
||
47 | */ |
||
48 | protected function configure(): void |
||
49 | { |
||
50 | $prefix = $this->isStandaloneSculpin() ? '' : 'sculpin:'; |
||
51 | |||
52 | $this |
||
53 | ->setName($prefix.'generate') |
||
54 | ->setDescription('Generate a site from source.') |
||
55 | ->setDefinition([ |
||
56 | new InputOption( |
||
57 | 'clean', |
||
58 | null, |
||
59 | InputOption::VALUE_NONE, |
||
60 | 'Cleans the output directory prior to generation.' |
||
61 | ), |
||
62 | new InputOption( |
||
63 | 'watch', |
||
64 | null, |
||
65 | InputOption::VALUE_NONE, |
||
66 | 'Watch source and regenerate site as changes are made.' |
||
67 | ), |
||
68 | new InputOption( |
||
69 | 'server', |
||
70 | null, |
||
71 | InputOption::VALUE_NONE, |
||
72 | 'Start an HTTP server to host your generated site' |
||
73 | ), |
||
74 | new InputOption('url', null, InputOption::VALUE_REQUIRED, 'Override URL.'), |
||
75 | new InputOption('port', null, InputOption::VALUE_REQUIRED, 'Port'), |
||
76 | new InputOption('output-dir', null, InputOption::VALUE_REQUIRED, 'Output Directory'), |
||
77 | new InputOption('source-dir', null, InputOption::VALUE_REQUIRED, 'Source Directory'), |
||
78 | ]) |
||
79 | ->setHelp(<<<EOT |
||
80 | The <info>generate</info> command generates a site. |
||
81 | |||
82 | EOT |
||
83 | ); |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * {@inheritdoc} |
||
88 | */ |
||
89 | protected function execute(InputInterface $input, OutputInterface $output): void |
||
90 | { |
||
91 | $application = $this->getApplication(); |
||
92 | if ($application instanceof Application) { |
||
93 | foreach ($application->getMissingSculpinBundlesMessages() as $message) { |
||
94 | $output->writeln($message); |
||
95 | } |
||
96 | } |
||
97 | |||
98 | $writer = $this->getContainer()->get('sculpin.writer'); |
||
99 | $docroot = $writer->getOutputDir(); |
||
100 | if ($input->getOption('clean')) { |
||
101 | $this->clean($input, $output, $docroot); |
||
102 | } |
||
103 | |||
104 | $watch = $input->getOption('watch') ?: false; |
||
105 | $sculpin = $this->getContainer()->get('sculpin'); |
||
106 | $dataSource = $this->getContainer()->get('sculpin.data_source'); |
||
107 | $sourceSet = new SourceSet(); |
||
108 | |||
109 | $config = $this->getContainer()->get('sculpin.site_configuration'); |
||
110 | if ($url = $input->getOption('url')) { |
||
111 | $config->set('url', $url); |
||
112 | } |
||
113 | |||
114 | $consoleIo = new ConsoleIo($input, $output, $this->getApplication()->getHelperSet()); |
||
0 ignored issues
–
show
|
|||
115 | |||
116 | if ($input->getOption('server')) { |
||
117 | $this->throwExceptions = false; |
||
118 | $output->isDebug(); |
||
119 | $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo); |
||
120 | |||
121 | $kernel = $this->getContainer()->get('kernel'); |
||
122 | |||
123 | $httpServer = new HttpServer( |
||
124 | $output, |
||
125 | $docroot, |
||
126 | $kernel->getEnvironment(), |
||
127 | $kernel->isDebug(), |
||
128 | (int) $input->getOption('port') |
||
129 | ); |
||
130 | |||
131 | if ($watch) { |
||
132 | $httpServer->addPeriodicTimer(1, function () use ($sculpin, $dataSource, $sourceSet, $consoleIo) { |
||
133 | clearstatcache(); |
||
134 | $sourceSet->reset(); |
||
135 | |||
136 | $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo); |
||
137 | }); |
||
138 | } |
||
139 | |||
140 | $httpServer->run(); |
||
141 | } else { |
||
142 | $this->throwExceptions = !$watch; |
||
143 | do { |
||
144 | $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo); |
||
145 | |||
146 | if ($watch) { |
||
147 | sleep(2); |
||
148 | clearstatcache(); |
||
149 | $sourceSet->reset(); |
||
150 | } |
||
151 | } while ($watch); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Cleanup an output directory by deleting it. |
||
157 | * |
||
158 | * @param string $dir The directory to remove |
||
159 | */ |
||
160 | private function clean(InputInterface $input, OutputInterface $output, string $dir): void |
||
161 | { |
||
162 | $fileSystem = $this->getContainer()->get('filesystem'); |
||
163 | |||
164 | if ($fileSystem->exists($dir)) { |
||
165 | if ($input->isInteractive()) { |
||
166 | // Prompt the user for confirmation. |
||
167 | /** @var QuestionHelper $helper */ |
||
168 | $helper = $this->getHelper('question'); |
||
169 | $question = new ConfirmationQuestion(sprintf( |
||
170 | 'Are you sure you want to delete all the contents of the %s directory?', |
||
171 | $dir |
||
172 | ), false); |
||
173 | |||
174 | if (!$helper->ask($input, $output, $question)) { |
||
175 | return; |
||
176 | } |
||
177 | } |
||
178 | |||
179 | $output->writeln(sprintf('Deleting %s', $dir)); |
||
180 | $fileSystem->remove($dir); |
||
181 | } |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * @throws \Throwable |
||
186 | */ |
||
187 | protected function runSculpin( |
||
188 | Sculpin $sculpin, |
||
189 | DataSourceInterface $dataSource, |
||
190 | SourceSet $sourceSet, |
||
191 | IoInterface $io |
||
192 | ) { |
||
193 | $messages = []; |
||
194 | $errPrint = function (\Exception $e) { |
||
195 | return $e->getMessage().PHP_EOL.' at '.str_replace(getcwd().DIRECTORY_SEPARATOR, '', $e->getFile()); |
||
196 | }; |
||
197 | |||
198 | try { |
||
199 | $sculpin->run($dataSource, $sourceSet, $io); |
||
200 | |||
201 | return; |
||
202 | } catch (LoaderError | RuntimeError | SyntaxError $e) { |
||
203 | $messages[] = '<error>Twig exception: ' . $errPrint($e) . '</error>'; |
||
204 | } catch (IOException $e) { |
||
205 | $messages[] = '<error>Filesystem exception: ' . $errPrint($e) . '</error>'; |
||
206 | } catch (\Throwable $e) { |
||
207 | $messages[] = '<error>Exception: ' . $errPrint($e) . '</error>'; |
||
208 | } |
||
209 | |||
210 | if ($this->throwExceptions) { |
||
211 | throw $e; |
||
212 | } |
||
213 | |||
214 | if ($io->isDebug()) { |
||
215 | $messages[] = '<comment>Exception trace:</comment>'; |
||
216 | |||
217 | foreach ($e->getTrace() as $trace) { |
||
218 | $messages[] = sprintf( |
||
219 | '<comment> %s at %s:%s</comment>', |
||
220 | isset($trace['class']) ? $trace['class'] . '->' . $trace['function'] : $trace['function'], |
||
221 | $trace['file'], |
||
222 | $trace['line'] |
||
223 | ); |
||
224 | } |
||
225 | } |
||
226 | |||
227 | $io->write('<error>[FAILED]</error>'); |
||
228 | foreach ($messages as $message) { |
||
229 | $io->write($message); |
||
230 | } |
||
231 | $io->write(''); |
||
232 | } |
||
233 | } |
||
234 |
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.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.