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 N98\Magento\Command; |
||
4 | |||
5 | use Composer\Package\PackageInterface; |
||
6 | use InvalidArgumentException; |
||
7 | use N98\Util\OperatingSystem; |
||
8 | use RuntimeException; |
||
9 | use Symfony\Component\Console\Command\Command; |
||
10 | use Symfony\Component\Console\Input\InputInterface; |
||
11 | use Symfony\Component\Console\Output\OutputInterface; |
||
12 | use Composer\Package\Loader\ArrayLoader as PackageLoader; |
||
13 | use Composer\Factory as ComposerFactory; |
||
14 | use Composer\IO\ConsoleIO; |
||
15 | use N98\Util\Console\Helper\MagentoHelper; |
||
16 | |||
17 | /** |
||
18 | * Class AbstractMagentoCommand |
||
19 | * |
||
20 | * @package N98\Magento\Command |
||
21 | * |
||
22 | * @method \N98\Magento\Application getApplication() getApplication() |
||
23 | */ |
||
24 | abstract class AbstractMagentoCommand extends Command |
||
25 | { |
||
26 | /** |
||
27 | * @var int |
||
28 | */ |
||
29 | const MAGENTO_MAJOR_VERSION_1 = 1; |
||
30 | |||
31 | /** |
||
32 | * @var int |
||
33 | */ |
||
34 | const MAGENTO_MAJOR_VERSION_2 = 2; |
||
35 | |||
36 | /** |
||
37 | * @var string |
||
38 | */ |
||
39 | protected $_magentoRootFolder = null; |
||
40 | |||
41 | /** |
||
42 | * @var int |
||
43 | */ |
||
44 | protected $_magentoMajorVersion = self::MAGENTO_MAJOR_VERSION_1; |
||
45 | |||
46 | /** |
||
47 | * @var bool |
||
48 | */ |
||
49 | protected $_magentoEnterprise = false; |
||
50 | |||
51 | /** |
||
52 | * @var array |
||
53 | */ |
||
54 | protected $_deprecatedAlias = array(); |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | */ |
||
59 | protected $_websiteCodeMap = array(); |
||
60 | |||
61 | /** |
||
62 | * Initializes the command just after the input has been validated. |
||
63 | * |
||
64 | * This is mainly useful when a lot of commands extends one main command |
||
65 | * where some things need to be initialized based on the input arguments and options. |
||
66 | * |
||
67 | * @param InputInterface $input An InputInterface instance |
||
68 | * @param OutputInterface $output An OutputInterface instance |
||
69 | */ |
||
70 | protected function initialize(InputInterface $input, OutputInterface $output) |
||
71 | { |
||
72 | $this->checkDeprecatedAliases($input, $output); |
||
73 | } |
||
74 | |||
75 | private function _initWebsites() |
||
76 | { |
||
77 | $this->_websiteCodeMap = array(); |
||
78 | /** @var \Mage_Core_Model_Website[] $websites */ |
||
79 | $websites = \Mage::app()->getWebsites(false); |
||
80 | foreach ($websites as $website) { |
||
81 | $this->_websiteCodeMap[$website->getId()] = $website->getCode(); |
||
82 | } |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * @param int $websiteId |
||
87 | * @return string |
||
88 | */ |
||
89 | protected function _getWebsiteCodeById($websiteId) |
||
90 | { |
||
91 | if (empty($this->_websiteCodeMap)) { |
||
92 | $this->_initWebsites(); |
||
93 | } |
||
94 | |||
95 | if (isset($this->_websiteCodeMap[$websiteId])) { |
||
96 | return $this->_websiteCodeMap[$websiteId]; |
||
97 | } |
||
98 | |||
99 | return ''; |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * @param string $websiteCode |
||
104 | * @return int |
||
105 | */ |
||
106 | protected function _getWebsiteIdByCode($websiteCode) |
||
107 | { |
||
108 | if (empty($this->_websiteCodeMap)) { |
||
109 | $this->_initWebsites(); |
||
110 | } |
||
111 | $websiteMap = array_flip($this->_websiteCodeMap); |
||
112 | |||
113 | return $websiteMap[$websiteCode]; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * @param string|null $commandClass |
||
118 | * @return array |
||
119 | */ |
||
120 | protected function getCommandConfig($commandClass = null) |
||
121 | { |
||
122 | if (null === $commandClass) { |
||
123 | $commandClass = get_class($this); |
||
124 | } |
||
125 | |||
126 | $configArray = $this->getApplication()->getConfig(); |
||
127 | if (isset($configArray['commands'][$commandClass])) { |
||
128 | return $configArray['commands'][$commandClass]; |
||
129 | } |
||
130 | |||
131 | return null; |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * @param OutputInterface $output |
||
136 | * @param string $text |
||
137 | * @param string $style |
||
138 | */ |
||
139 | protected function writeSection(OutputInterface $output, $text, $style = 'bg=blue;fg=white') |
||
140 | { |
||
141 | $output->writeln(array( |
||
142 | '', |
||
143 | $this->getHelperSet()->get('formatter')->formatBlock($text, $style, true), |
||
144 | '', |
||
145 | )); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Bootstrap magento shop |
||
150 | * |
||
151 | * @param bool $soft |
||
152 | * @return bool |
||
153 | */ |
||
154 | protected function initMagento($soft = false) |
||
155 | { |
||
156 | $init = $this->getApplication()->initMagento($soft); |
||
157 | if ($init) { |
||
158 | $this->_magentoRootFolder = $this->getApplication()->getMagentoRootFolder(); |
||
159 | } |
||
160 | |||
161 | return $init; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Search for magento root folder |
||
166 | * |
||
167 | * @param OutputInterface $output |
||
168 | * @param bool $silent print debug messages |
||
169 | * @throws RuntimeException |
||
170 | */ |
||
171 | public function detectMagento(OutputInterface $output, $silent = true) |
||
172 | { |
||
173 | $this->getApplication()->detectMagento(); |
||
174 | |||
175 | $this->_magentoEnterprise = $this->getApplication()->isMagentoEnterprise(); |
||
176 | $this->_magentoRootFolder = $this->getApplication()->getMagentoRootFolder(); |
||
177 | $this->_magentoMajorVersion = $this->getApplication()->getMagentoMajorVersion(); |
||
178 | |||
179 | if (!$silent) { |
||
180 | $editionString = ($this->_magentoEnterprise ? ' (Enterprise Edition) ' : ''); |
||
181 | $output->writeln('<info>Found Magento ' . $editionString . 'in folder "' . $this->_magentoRootFolder . '"</info>'); |
||
182 | } |
||
183 | |||
184 | if (!empty($this->_magentoRootFolder)) { |
||
185 | return; |
||
186 | } |
||
187 | |||
188 | throw new RuntimeException('Magento folder could not be detected'); |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Die if not Enterprise |
||
193 | */ |
||
194 | protected function requireEnterprise(OutputInterface $output) |
||
195 | { |
||
196 | if (!$this->_magentoEnterprise) { |
||
197 | $output->writeln('<error>Enterprise Edition is required but was not detected</error>'); |
||
198 | exit; |
||
199 | } |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * @return \Mage_Core_Helper_Data |
||
204 | */ |
||
205 | protected function getCoreHelper() |
||
206 | { |
||
207 | if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) { |
||
208 | return \Mage::helper('Mage_Core_Helper_Data'); |
||
209 | } |
||
210 | return \Mage::helper('core'); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * @param InputInterface $input |
||
215 | * @param OutputInterface $output |
||
216 | * @return \Composer\Downloader\DownloadManager |
||
217 | */ |
||
218 | protected function getComposerDownloadManager($input, $output) |
||
219 | { |
||
220 | return $this->getComposer($input, $output)->getDownloadManager(); |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * @param array|PackageInterface $config |
||
225 | * @return \Composer\Package\CompletePackage |
||
226 | */ |
||
227 | protected function createComposerPackageByConfig($config) |
||
228 | { |
||
229 | $packageLoader = new PackageLoader(); |
||
230 | return $packageLoader->load($config); |
||
0 ignored issues
–
show
|
|||
231 | } |
||
232 | |||
233 | /** |
||
234 | * @param InputInterface $input |
||
235 | * @param OutputInterface $output |
||
236 | * @param array|PackageInterface $config |
||
237 | * @param string $targetFolder |
||
238 | * @param bool $preferSource |
||
239 | * @return \Composer\Package\CompletePackage |
||
240 | */ |
||
241 | protected function downloadByComposerConfig(InputInterface $input, OutputInterface $output, $config, $targetFolder, |
||
242 | $preferSource = true |
||
243 | ) { |
||
244 | $dm = $this->getComposerDownloadManager($input, $output); |
||
245 | if (!$config instanceof PackageInterface) { |
||
246 | $package = $this->createComposerPackageByConfig($config); |
||
247 | } else { |
||
248 | $package = $config; |
||
249 | } |
||
250 | |||
251 | $helper = new \N98\Util\Console\Helper\MagentoHelper(); |
||
252 | $helper->detect($targetFolder); |
||
253 | if ($this->isSourceTypeRepository($package->getSourceType()) && $helper->getRootFolder() == $targetFolder) { |
||
254 | $package->setInstallationSource('source'); |
||
255 | $this->checkRepository($package, $targetFolder); |
||
256 | $dm->update($package, $package, $targetFolder); |
||
257 | } else { |
||
258 | $dm->download($package, $targetFolder, $preferSource); |
||
259 | } |
||
260 | |||
261 | return $package; |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * brings locally cached repository up to date if it is missing the requested tag |
||
266 | * |
||
267 | * @param PackageInterface $package |
||
268 | * @param string $targetFolder |
||
269 | */ |
||
270 | protected function checkRepository($package, $targetFolder) |
||
271 | { |
||
272 | if ($package->getSourceType() == 'git') { |
||
273 | $command = sprintf( |
||
274 | 'cd %s && git rev-parse refs/tags/%s', |
||
275 | escapeshellarg($this->normalizePath($targetFolder)), |
||
276 | escapeshellarg($package->getSourceReference()) |
||
277 | ); |
||
278 | $existingTags = shell_exec($command); |
||
279 | if (!$existingTags) { |
||
280 | $command = sprintf('cd %s && git fetch', escapeshellarg($this->normalizePath($targetFolder))); |
||
281 | shell_exec($command); |
||
282 | } |
||
283 | } elseif ($package->getSourceType() == 'hg') { |
||
284 | $command = sprintf( |
||
285 | 'cd %s && hg log --template "{tags}" -r %s', |
||
286 | escapeshellarg($targetFolder), |
||
287 | escapeshellarg($package->getSourceReference()) |
||
288 | ); |
||
289 | $existingTag = shell_exec($command); |
||
290 | if ($existingTag === $package->getSourceReference()) { |
||
291 | $command = sprintf('cd %s && hg pull', escapeshellarg($targetFolder)); |
||
292 | shell_exec($command); |
||
293 | } |
||
294 | } |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * normalize paths on windows / cygwin / msysgit |
||
299 | * |
||
300 | * when using a path value that has been created in a cygwin shell but then PHP uses it inside a cmd shell it needs |
||
301 | * to be filtered. |
||
302 | * |
||
303 | * @param string $path |
||
304 | * @return string |
||
305 | */ |
||
306 | protected function normalizePath($path) |
||
307 | { |
||
308 | if (defined('PHP_WINDOWS_VERSION_BUILD')) { |
||
309 | $path = strtr($path, '/', '\\'); |
||
310 | } |
||
311 | return $path; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * obtain composer |
||
316 | * |
||
317 | * @param InputInterface $input |
||
318 | * @param OutputInterface $output |
||
319 | * |
||
320 | * @return \Composer\Composer |
||
321 | */ |
||
322 | protected function getComposer(InputInterface $input, OutputInterface $output) |
||
323 | { |
||
324 | $io = new ConsoleIO($input, $output, $this->getHelperSet()); |
||
325 | return ComposerFactory::create($io, array()); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * @param string $alias |
||
330 | * @param string $message |
||
331 | * @return AbstractMagentoCommand |
||
332 | */ |
||
333 | protected function addDeprecatedAlias($alias, $message) |
||
334 | { |
||
335 | $this->_deprecatedAlias[$alias] = $message; |
||
336 | |||
337 | return $this; |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * @param InputInterface $input |
||
342 | * @param OutputInterface $output |
||
343 | */ |
||
344 | protected function checkDeprecatedAliases(InputInterface $input, OutputInterface $output) |
||
345 | { |
||
346 | if (isset($this->_deprecatedAlias[$input->getArgument('command')])) { |
||
347 | $output->writeln('<error>Deprecated:</error> <comment>' . $this->_deprecatedAlias[$input->getArgument('command')] . '</comment>'); |
||
348 | } |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Magento 1 / 2 switches |
||
353 | * |
||
354 | * @param string $mage1code Magento 1 class code |
||
355 | * @param string $mage2class Magento 2 class name |
||
356 | * @return \Mage_Core_Model_Abstract |
||
357 | */ |
||
358 | protected function _getModel($mage1code, $mage2class) |
||
359 | { |
||
360 | if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) { |
||
361 | return \Mage::getModel($mage2class); |
||
362 | } else { |
||
363 | return \Mage::getModel($mage1code); |
||
364 | } |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Magento 1 / 2 switches |
||
369 | * |
||
370 | * @param string $mage1code Magento 1 class code |
||
371 | * @param string $mage2class Magento 2 class name |
||
372 | * @return \Mage_Core_Model_Abstract |
||
373 | */ |
||
374 | protected function _getResourceModel($mage1code, $mage2class) |
||
375 | { |
||
376 | if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) { |
||
377 | return \Mage::getResourceModel($mage2class); |
||
378 | } else { |
||
379 | return \Mage::getResourceModel($mage1code); |
||
380 | } |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * Magento 1 / 2 switches |
||
385 | * |
||
386 | * @param string $mage1code Magento 1 class code |
||
387 | * @param string $mage2class Magento 2 class name |
||
388 | * @return \Mage_Core_Model_Abstract |
||
389 | */ |
||
390 | protected function _getResourceSingleton($mage1code, $mage2class) |
||
391 | { |
||
392 | if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) { |
||
393 | return \Mage::getResourceSingleton($mage2class); |
||
394 | } else { |
||
395 | return \Mage::getResourceSingleton($mage1code); |
||
396 | } |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * @param string $value |
||
401 | * @return bool |
||
402 | */ |
||
403 | protected function _parseBoolOption($value) |
||
404 | { |
||
405 | return in_array(strtolower($value), array('y', 'yes', 1, 'true')); |
||
406 | } |
||
407 | |||
408 | /** |
||
409 | * @param string $value |
||
410 | * @return string |
||
411 | */ |
||
412 | protected function formatActive($value) |
||
413 | { |
||
414 | if (in_array($value, array(1, 'true'))) { |
||
415 | return 'active'; |
||
416 | } |
||
417 | |||
418 | return 'inactive'; |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * @param InputInterface $input |
||
423 | * @param OutputInterface $output |
||
424 | * |
||
425 | * @return int |
||
426 | */ |
||
427 | public function run(InputInterface $input, OutputInterface $output) |
||
428 | { |
||
429 | $this->getHelperSet()->setCommand($this); |
||
430 | |||
431 | return parent::run($input, $output); |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * @param InputInterface $input |
||
436 | * @param OutputInterface $output |
||
437 | */ |
||
438 | protected function chooseInstallationFolder(InputInterface $input, OutputInterface $output) |
||
439 | { |
||
440 | /** |
||
441 | * @param string $folderName |
||
442 | * |
||
443 | * @return string |
||
444 | */ |
||
445 | $validateInstallationFolder = function($folderName) use ($input) { |
||
446 | |||
447 | $folderName = rtrim(trim($folderName, ' '), '/'); |
||
448 | // resolve folder-name to current working directory if relative |
||
449 | if (substr($folderName, 0, 1) == '.') { |
||
450 | $cwd = OperatingSystem::getCwd(); |
||
451 | $folderName = $cwd . substr($folderName, 1); |
||
452 | } |
||
453 | |||
454 | if (empty($folderName)) { |
||
455 | throw new InvalidArgumentException('Installation folder cannot be empty'); |
||
456 | } |
||
457 | |||
458 | if (!is_dir($folderName)) { |
||
459 | if (!@mkdir($folderName, 0777, true)) { |
||
460 | throw new InvalidArgumentException('Cannot create folder.'); |
||
461 | } |
||
462 | |||
463 | return $folderName; |
||
464 | } |
||
465 | |||
466 | if ($input->hasOption('noDownload') && $input->getOption('noDownload')) { |
||
467 | /** @var MagentoHelper $magentoHelper */ |
||
468 | $magentoHelper = new MagentoHelper(); |
||
469 | $magentoHelper->detect($folderName); |
||
470 | if ($magentoHelper->getRootFolder() !== $folderName) { |
||
471 | throw new InvalidArgumentException( |
||
472 | sprintf( |
||
473 | 'Folder %s is not a Magento working copy.', |
||
474 | $folderName |
||
475 | ) |
||
476 | ); |
||
477 | } |
||
478 | |||
479 | $localXml = $folderName . '/app/etc/local.xml'; |
||
480 | if (file_exists($localXml)) { |
||
481 | throw new InvalidArgumentException( |
||
482 | sprintf( |
||
483 | 'Magento working copy in %s seems already installed. Please remove %s and retry.', |
||
484 | $folderName, |
||
485 | $localXml |
||
486 | ) |
||
487 | ); |
||
488 | } |
||
489 | } |
||
490 | |||
491 | return $folderName; |
||
492 | }; |
||
493 | |||
494 | if (($installationFolder = $input->getOption('installationFolder')) == null) { |
||
495 | $defaultFolder = './magento'; |
||
496 | $question[] = "<question>Enter installation folder:</question> [<comment>" . $defaultFolder . "</comment>]"; |
||
497 | |||
498 | $installationFolder = $this->getHelper('dialog')->askAndValidate($output, $question, $validateInstallationFolder, false, $defaultFolder); |
||
499 | |||
500 | } else { |
||
501 | // @Todo improve validation and bring it to 1 single function |
||
502 | $installationFolder = $validateInstallationFolder($installationFolder); |
||
503 | |||
504 | } |
||
505 | |||
506 | $this->config['installationFolder'] = realpath($installationFolder); |
||
507 | \chdir($this->config['installationFolder']); |
||
508 | } |
||
509 | |||
510 | /** |
||
511 | * @param string $type |
||
512 | * |
||
513 | * @return bool |
||
514 | */ |
||
515 | protected function isSourceTypeRepository($type) |
||
516 | { |
||
517 | return in_array($type, array('git', 'hg')); |
||
518 | } |
||
519 | |||
520 | /** |
||
521 | * @param string $argument |
||
522 | * @param InputInterface $input |
||
523 | * @param OutputInterface $output |
||
524 | * @param string $message |
||
525 | * @return string |
||
526 | */ |
||
527 | protected function getOrAskForArgument($argument, InputInterface $input, OutputInterface $output, $message = null) |
||
528 | { |
||
529 | $inputArgument = $input->getArgument($argument); |
||
530 | if ($inputArgument === null) { |
||
531 | |||
532 | $message = $this->getArgumentMessage($argument, $message); |
||
533 | |||
534 | /** @var $dialog \Symfony\Component\Console\Helper\DialogHelper */ |
||
535 | $dialog = $this->getHelperSet()->get('dialog'); |
||
536 | return $dialog->ask($output, $message); |
||
537 | } |
||
538 | |||
539 | return $inputArgument; |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * @param array $entries zero-indexed array of entries (represented by strings) to select from |
||
544 | * @param OutputInterface $output |
||
545 | * @param string $question |
||
546 | */ |
||
547 | protected function askForArrayEntry(array $entries, OutputInterface $output, $question) |
||
548 | { |
||
549 | $dialog = ''; |
||
550 | foreach ($entries as $key => $entry) { |
||
551 | $dialog .= '<comment>[' . ($key + 1) . ']</comment> ' . $entry . "\n"; |
||
552 | } |
||
553 | $dialog .= "<question>{$question}</question> "; |
||
554 | |||
555 | $selected = $this->getHelper('dialog')->askAndValidate($output, $dialog, function($typeInput) use ($entries) { |
||
556 | if (!in_array($typeInput, range(1, count($entries)))) { |
||
557 | throw new InvalidArgumentException('Invalid type'); |
||
558 | } |
||
559 | |||
560 | return $typeInput; |
||
561 | }); |
||
562 | |||
563 | return $entries[$selected - 1]; |
||
564 | } |
||
565 | |||
566 | /** |
||
567 | * @param string $argument |
||
568 | * @param string $message [optional] |
||
569 | * @return string |
||
570 | */ |
||
571 | protected function getArgumentMessage($argument, $message = null) |
||
572 | { |
||
573 | if (null === $message) { |
||
574 | $message = ucfirst($argument); |
||
575 | } |
||
576 | |||
577 | return sprintf('<question>%s:</question>', $message); |
||
578 | } |
||
579 | } |
||
580 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.