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\Installer; |
||
4 | |||
5 | use Composer\Composer; |
||
6 | use Composer\Package\CompletePackage; |
||
7 | use Exception; |
||
8 | use InvalidArgumentException; |
||
9 | use N98\Magento\Command\AbstractMagentoCommand; |
||
10 | use N98\Util\Database as DatabaseUtils; |
||
11 | use N98\Util\Filesystem; |
||
12 | use N98\Util\OperatingSystem; |
||
13 | use N98\Util\BinaryString; |
||
14 | use PDO; |
||
15 | use PDOException; |
||
16 | use RuntimeException; |
||
17 | use Symfony\Component\Console\Input\InputInterface; |
||
18 | use Symfony\Component\Console\Input\InputOption; |
||
19 | use Symfony\Component\Console\Input\StringInput; |
||
20 | use Symfony\Component\Console\Output\OutputInterface; |
||
21 | use Symfony\Component\Finder\Finder; |
||
22 | use N98\Util\Exec; |
||
23 | |||
24 | /** |
||
25 | * Class InstallCommand |
||
26 | * |
||
27 | * @codeCoverageIgnore - Travis server uses installer to create a new shop. If it not works complete build fails. |
||
28 | * @package N98\Magento\Command\Installer |
||
29 | */ |
||
30 | class InstallCommand extends AbstractMagentoCommand |
||
31 | { |
||
32 | const EXEC_STATUS_OK = 0; |
||
33 | /** |
||
34 | * @var array |
||
35 | */ |
||
36 | protected $config; |
||
37 | |||
38 | /** |
||
39 | * @var array |
||
40 | */ |
||
41 | protected $_argv; |
||
42 | |||
43 | /** |
||
44 | * @var array |
||
45 | */ |
||
46 | protected $commandConfig; |
||
47 | |||
48 | /** |
||
49 | * @var \Closure |
||
50 | */ |
||
51 | protected $notEmptyCallback; |
||
52 | |||
53 | protected function configure() |
||
54 | { |
||
55 | $this |
||
56 | ->setName('install') |
||
57 | ->addOption('magentoVersion', null, InputOption::VALUE_OPTIONAL, 'Magento version') |
||
58 | ->addOption('magentoVersionByName', null, InputOption::VALUE_OPTIONAL, 'Magento version name instead of order number') |
||
59 | ->addOption('installationFolder', null, InputOption::VALUE_OPTIONAL, 'Installation folder') |
||
60 | ->addOption('dbHost', null, InputOption::VALUE_OPTIONAL, 'Database host') |
||
61 | ->addOption('dbUser', null, InputOption::VALUE_OPTIONAL, 'Database user') |
||
62 | ->addOption('dbPass', null, InputOption::VALUE_OPTIONAL, 'Database password') |
||
63 | ->addOption('dbName', null, InputOption::VALUE_OPTIONAL, 'Database name') |
||
64 | ->addOption('dbPort', null, InputOption::VALUE_OPTIONAL, 'Database port', 3306) |
||
65 | ->addOption('dbPrefix', null, InputOption::VALUE_OPTIONAL, 'Table prefix', '') |
||
66 | ->addOption('installSampleData', null, InputOption::VALUE_OPTIONAL, 'Install sample data') |
||
67 | ->addOption('useDefaultConfigParams', null, InputOption::VALUE_OPTIONAL, 'Use default installation parameters defined in the yaml file') |
||
68 | ->addOption('baseUrl', null, InputOption::VALUE_OPTIONAL, 'Installation base url') |
||
69 | ->addOption('replaceHtaccessFile', null, InputOption::VALUE_OPTIONAL, 'Generate htaccess file (for non vhost environment)') |
||
70 | ->addOption( |
||
71 | 'noDownload', |
||
72 | null, |
||
73 | InputOption::VALUE_NONE, |
||
74 | 'If set skips download step. Used when installationFolder is already a Magento installation that has ' . |
||
75 | 'to be installed on the given database.' |
||
76 | ) |
||
77 | ->addOption( |
||
78 | 'only-download', |
||
79 | null, |
||
80 | InputOption::VALUE_NONE, |
||
81 | 'Downloads (and extracts) source code' |
||
82 | ) |
||
83 | ->addOption('forceUseDb', null, InputOption::VALUE_OPTIONAL, 'If --noDownload passed, force to use given database if it already exists.') |
||
84 | ->setDescription('Install magento') |
||
85 | ; |
||
86 | |||
87 | $help = <<<HELP |
||
88 | * Download Magento by a list of git repos and zip files (mageplus, magelte, official community packages). |
||
89 | * Try to create database if it does not exist. |
||
90 | * Installs Magento sample data if available (since version 1.2.0). |
||
91 | * Starts Magento installer |
||
92 | * Sets rewrite base in .htaccess file |
||
93 | |||
94 | Example of an unattended Magento CE 1.7.0.2 installation: |
||
95 | |||
96 | $ n98-magerun.phar install --dbHost="localhost" --dbUser="mydbuser" --dbPass="mysecret" --dbName="magentodb" --installSampleData=yes --useDefaultConfigParams=yes --magentoVersionByName="magento-ce-1.7.0.2" --installationFolder="magento" --baseUrl="http://magento.localdomain/" |
||
97 | |||
98 | Additionally, with --noDownload option you can install Magento working copy already stored in --installationFolder on |
||
99 | the given database. |
||
100 | |||
101 | See it in action: http://youtu.be/WU-CbJ86eQc |
||
102 | |||
103 | HELP; |
||
104 | $this->setHelp($help); |
||
105 | |||
106 | $this->notEmptyCallback = function($input) |
||
107 | { |
||
108 | if (empty($input)) { |
||
109 | throw new InvalidArgumentException('Please enter a value'); |
||
110 | } |
||
111 | return $input; |
||
112 | }; |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * @return bool |
||
117 | */ |
||
118 | public function isEnabled() |
||
119 | { |
||
120 | return Exec::allowed(); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * @param InputInterface $input |
||
125 | * @param OutputInterface $output |
||
126 | * @throws RuntimeException |
||
127 | * @return int|null|void |
||
128 | */ |
||
129 | protected function execute(InputInterface $input, OutputInterface $output) |
||
130 | { |
||
131 | $this->commandConfig = $this->getCommandConfig(); |
||
132 | $this->writeSection($output, 'Magento Installation'); |
||
133 | |||
134 | $this->precheckPhp(); |
||
135 | |||
136 | if (!$input->getOption('noDownload')) { |
||
137 | $this->selectMagentoVersion($input, $output); |
||
138 | } |
||
139 | |||
140 | $this->chooseInstallationFolder($input, $output); |
||
141 | |||
142 | if (!$input->getOption('noDownload')) { |
||
143 | $result = $this->downloadMagento($input, $output); |
||
144 | |||
145 | if ($result === false) { |
||
146 | return 1; |
||
147 | } |
||
148 | } |
||
149 | |||
150 | if ($input->getOption('only-download')) { |
||
151 | return 0; |
||
152 | } |
||
153 | |||
154 | $this->createDatabase($input, $output); |
||
155 | |||
156 | if (!$input->getOption('noDownload')) { |
||
157 | $this->installSampleData($input, $output); |
||
158 | } |
||
159 | |||
160 | $this->removeEmptyFolders(); |
||
161 | $this->setDirectoryPermissions($output); |
||
162 | $this->installMagento($input, $output, $this->config['installationFolder']); |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Check PHP environment agains minimal required settings modules |
||
167 | */ |
||
168 | protected function precheckPhp() |
||
169 | { |
||
170 | $extensions = $this->commandConfig['installation']['pre-check']['php']['extensions']; |
||
171 | $missingExtensions = array(); |
||
172 | foreach ($extensions as $extension) { |
||
173 | if (!extension_loaded($extension)) { |
||
174 | $missingExtensions[] = $extension; |
||
175 | } |
||
176 | } |
||
177 | |||
178 | if (count($missingExtensions) > 0) { |
||
179 | throw new RuntimeException( |
||
180 | 'The following PHP extensions are required to start installation: ' . implode(',', $missingExtensions) |
||
181 | ); |
||
182 | } |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * @param InputInterface $input |
||
187 | * @param OutputInterface $output |
||
188 | * |
||
189 | * @throws InvalidArgumentException |
||
190 | */ |
||
191 | protected function selectMagentoVersion(InputInterface $input, OutputInterface $output) |
||
192 | { |
||
193 | if ($input->getOption('magentoVersion') == null && $input->getOption('magentoVersionByName') == null) { |
||
194 | $question = array(); |
||
195 | foreach ($this->commandConfig['magento-packages'] as $key => $package) { |
||
196 | $question[] = '<comment>' . str_pad('[' . ($key + 1) . ']', 4, ' ') . '</comment> ' . $package['name'] . "\n"; |
||
197 | } |
||
198 | $question[] = "<question>Choose a magento version:</question> "; |
||
199 | |||
200 | $commandConfig = $this->commandConfig; |
||
201 | |||
202 | |||
203 | $type = $this->getHelper('dialog')->askAndValidate($output, $question, function($typeInput) use ($commandConfig) { |
||
204 | if (!in_array($typeInput, range(1, count($commandConfig['magento-packages'])))) { |
||
205 | throw new InvalidArgumentException('Invalid type'); |
||
206 | } |
||
207 | |||
208 | return $typeInput; |
||
209 | }); |
||
210 | } else { |
||
211 | $type = null; |
||
212 | |||
213 | if ($input->getOption('magentoVersion')) { |
||
214 | $type = $input->getOption('magentoVersion'); |
||
215 | if ($type !== (string) (int) $type) { |
||
216 | $type = $this->getPackageNumberByName($type); |
||
217 | } |
||
218 | } elseif ($input->getOption('magentoVersionByName')) { |
||
219 | $type = $this->getPackageNumberByName($input->getOption('magentoVersionByName')); |
||
220 | } |
||
221 | |||
222 | if ($type == null) { |
||
223 | throw new InvalidArgumentException('Unable to locate Magento version'); |
||
224 | } |
||
225 | } |
||
226 | |||
227 | $magentoPackages = $this->commandConfig['magento-packages']; |
||
228 | |||
229 | $index = $type - 1; |
||
230 | if (!isset($magentoPackages[$index])) { |
||
231 | throw new InvalidArgumentException( |
||
232 | sprintf( |
||
233 | 'Invalid Magento package number %s, must be from 1 to %d.', var_export($type, true), |
||
234 | count($magentoPackages) |
||
235 | ) |
||
236 | ); |
||
237 | } |
||
238 | |||
239 | $this->config['magentoVersionData'] = $magentoPackages[$index]; |
||
240 | } |
||
241 | |||
242 | |||
243 | /** |
||
244 | * @param $name |
||
245 | * |
||
246 | * @return int 1 or greater as the one-based package number, null on failure to resolve the name |
||
247 | */ |
||
248 | private function getPackageNumberByName($name) |
||
249 | { |
||
250 | // directly filter integer strings |
||
251 | if ($name === (string) (int) $name) { |
||
252 | return (int) $name; |
||
253 | } |
||
254 | |||
255 | $magentoPackages = $this->commandConfig['magento-packages']; |
||
256 | |||
257 | foreach ($magentoPackages as $key => $package) { |
||
258 | if ($package['name'] === $name) { |
||
259 | return $key + 1; |
||
260 | } |
||
261 | } |
||
262 | |||
263 | return null; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * @param InputInterface $input |
||
268 | * @param OutputInterface $output |
||
269 | * @return bool |
||
270 | */ |
||
271 | public function downloadMagento(InputInterface $input, OutputInterface $output) |
||
272 | { |
||
273 | try { |
||
274 | $package = $this->createComposerPackageByConfig($this->config['magentoVersionData']); |
||
275 | $this->config['magentoPackage'] = $package; |
||
276 | |||
277 | if (file_exists($this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Mage.php')) { |
||
278 | $output->writeln('<error>A magento installation already exists in this folder </error>'); |
||
279 | return false; |
||
280 | } |
||
281 | |||
282 | $composer = $this->getComposer($input, $output); |
||
283 | $targetFolder = $this->getTargetFolderByType($composer, $package, $this->config['installationFolder']); |
||
284 | $this->config['magentoPackage'] = $this->downloadByComposerConfig( |
||
285 | $input, |
||
286 | $output, |
||
287 | $package, |
||
288 | $targetFolder, |
||
289 | true |
||
290 | ); |
||
291 | |||
292 | if ($this->isSourceTypeRepository($package->getSourceType())) { |
||
293 | $filesystem = new \N98\Util\Filesystem; |
||
294 | $filesystem->recursiveCopy($targetFolder, $this->config['installationFolder'], array('.git', '.hg')); |
||
295 | } else { |
||
296 | $filesystem = new \Composer\Util\Filesystem(); |
||
297 | $filesystem->copyThenRemove( |
||
298 | $this->config['installationFolder'] . '/_n98_magerun_download', $this->config['installationFolder'] |
||
299 | ); |
||
300 | } |
||
301 | |||
302 | if (version_compare(PHP_VERSION, '5.4.0') >= 0) { |
||
303 | // Patch installer |
||
304 | $this->patchMagentoInstallerForPHP54($this->config['installationFolder']); |
||
305 | } |
||
306 | } catch (Exception $e) { |
||
307 | $output->writeln('<error>' . $e->getMessage() . '</error>'); |
||
308 | return false; |
||
309 | } |
||
310 | |||
311 | return true; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * construct a folder to where magerun will download the source to, cache git/hg repositories under COMPOSER_HOME |
||
316 | * |
||
317 | * @param Composer $composer |
||
318 | * @param CompletePackage $package |
||
319 | * @param $installationFolder |
||
320 | * |
||
321 | * @return string |
||
322 | */ |
||
323 | protected function getTargetFolderByType(Composer $composer, CompletePackage $package, $installationFolder) |
||
324 | { |
||
325 | $type = $package->getSourceType(); |
||
326 | if ($this->isSourceTypeRepository($type)) { |
||
327 | $targetPath = sprintf( |
||
328 | '%s/%s/%s/%s', |
||
329 | $composer->getConfig()->get('cache-dir'), |
||
330 | '_n98_magerun_download', |
||
331 | $type, |
||
332 | preg_replace('{[^a-z0-9.]}i', '-', $package->getSourceUrl()) |
||
333 | ); |
||
334 | } else { |
||
335 | $targetPath = sprintf( |
||
336 | '%s/%s', |
||
337 | $installationFolder, |
||
338 | '_n98_magerun_download' |
||
339 | ); |
||
340 | } |
||
341 | return $targetPath; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * @param string $magentoFolder |
||
346 | */ |
||
347 | protected function patchMagentoInstallerForPHP54($magentoFolder) |
||
348 | { |
||
349 | $installerConfig = $magentoFolder |
||
350 | . DIRECTORY_SEPARATOR |
||
351 | . 'app/code/core/Mage/Install/etc/config.xml'; |
||
352 | if (file_exists($installerConfig)) { |
||
353 | $xml = file_get_contents($installerConfig); |
||
354 | file_put_contents($installerConfig, str_replace('<pdo_mysql/>', '<pdo_mysql>1</pdo_mysql>', $xml)); |
||
355 | } |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * @param InputInterface $input |
||
360 | * @param OutputInterface $output |
||
361 | * |
||
362 | * @throws InvalidArgumentException |
||
363 | */ |
||
364 | protected function createDatabase(InputInterface $input, OutputInterface $output) |
||
365 | { |
||
366 | $dbOptions = array('--dbHost', '--dbUser', '--dbPass', '--dbName'); |
||
367 | $dbOptionsFound = 0; |
||
368 | foreach ($dbOptions as $dbOption) { |
||
369 | foreach ($this->getCliArguments() as $definedCliOption) { |
||
370 | if (BinaryString::startsWith($definedCliOption, $dbOption)) { |
||
371 | $dbOptionsFound++; |
||
372 | } |
||
373 | } |
||
374 | } |
||
375 | |||
376 | $hasAllOptions = $dbOptionsFound == 4; |
||
377 | |||
378 | // if all database options were passed in at cmd line |
||
379 | if ($hasAllOptions) { |
||
380 | $this->config['db_host'] = $input->getOption('dbHost'); |
||
381 | $this->config['db_user'] = $input->getOption('dbUser'); |
||
382 | $this->config['db_pass'] = $input->getOption('dbPass'); |
||
383 | $this->config['db_name'] = $input->getOption('dbName'); |
||
384 | $this->config['db_port'] = $input->getOption('dbPort'); |
||
385 | $this->config['db_prefix'] = $input->getOption('dbPrefix'); |
||
386 | $db = $this->validateDatabaseSettings($output, $input); |
||
387 | |||
388 | if ($db === false) { |
||
389 | throw new InvalidArgumentException("Database configuration is invalid"); |
||
390 | } |
||
391 | |||
392 | } else { |
||
393 | $dialog = $this->getHelperSet()->get('dialog'); |
||
394 | do { |
||
395 | $dbHostDefault = $input->getOption('dbHost') ? $input->getOption('dbHost') : 'localhost'; |
||
396 | $this->config['db_host'] = $dialog->askAndValidate($output, '<question>Please enter the database host</question> <comment>[' . $dbHostDefault . ']</comment>: ', $this->notEmptyCallback, false, $dbHostDefault); |
||
397 | |||
398 | $dbUserDefault = $input->getOption('dbUser') ? $input->getOption('dbUser') : 'root'; |
||
399 | $this->config['db_user'] = $dialog->askAndValidate($output, '<question>Please enter the database username</question> <comment>[' . $dbUserDefault . ']</comment>: ', $this->notEmptyCallback, false, $dbUserDefault); |
||
400 | |||
401 | $dbPassDefault = $input->getOption('dbPass') ? $input->getOption('dbPass') : ''; |
||
402 | $this->config['db_pass'] = $dialog->ask($output, '<question>Please enter the database password</question> <comment>[' . $dbPassDefault . ']</comment>: ', $dbPassDefault); |
||
403 | |||
404 | $dbNameDefault = $input->getOption('dbName') ? $input->getOption('dbName') : 'magento'; |
||
405 | $this->config['db_name'] = $dialog->askAndValidate($output, '<question>Please enter the database name</question> <comment>[' . $dbNameDefault . ']</comment>: ', $this->notEmptyCallback, false, $dbNameDefault); |
||
406 | |||
407 | $dbPortDefault = $input->getOption('dbPort') ? $input->getOption('dbPort') : 3306; |
||
408 | $this->config['db_port'] = $dialog->askAndValidate($output, '<question>Please enter the database port </question> <comment>[' . $dbPortDefault . ']</comment>: ', $this->notEmptyCallback, false, $dbPortDefault); |
||
409 | |||
410 | $dbPrefixDefault = $input->getOption('dbPrefix') ? $input->getOption('dbPrefix') : ''; |
||
411 | $this->config['db_prefix'] = $dialog->ask($output, '<question>Please enter the table prefix</question> <comment>[' . $dbPrefixDefault . ']</comment>:', $dbPrefixDefault); |
||
412 | $db = $this->validateDatabaseSettings($output, $input); |
||
413 | } while ($db === false); |
||
414 | } |
||
415 | |||
416 | $this->config['db'] = $db; |
||
417 | } |
||
418 | |||
419 | /** |
||
420 | * @param OutputInterface $output |
||
421 | * @param InputInterface $input |
||
422 | * |
||
423 | * @return bool|PDO |
||
424 | */ |
||
425 | protected function validateDatabaseSettings(OutputInterface $output, InputInterface $input) |
||
426 | { |
||
427 | try { |
||
428 | $dsn = sprintf("mysql:host=%s;port=%s", $this->config['db_host'], $this->config['db_port']); |
||
429 | $db = new PDO($dsn, $this->config['db_user'], $this->config['db_pass']); |
||
430 | if (!$db->query('USE ' . $this->config['db_name'])) { |
||
431 | $db->query("CREATE DATABASE `" . $this->config['db_name'] . "`"); |
||
432 | $output->writeln('<info>Created database ' . $this->config['db_name'] . '</info>'); |
||
433 | $db->query('USE ' . $this->config['db_name']); |
||
434 | |||
435 | return $db; |
||
436 | } |
||
437 | |||
438 | if ($input->getOption('noDownload') && !$input->getOption('forceUseDb')) { |
||
439 | $output->writeln("<error>Database {$this->config['db_name']} already exists.</error>"); |
||
440 | |||
441 | return false; |
||
442 | } |
||
443 | |||
444 | return $db; |
||
445 | } catch (PDOException $e) { |
||
446 | $output->writeln('<error>' . $e->getMessage() . '</error>'); |
||
447 | } |
||
448 | |||
449 | return false; |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * @param InputInterface $input |
||
454 | * @param OutputInterface $output |
||
455 | */ |
||
456 | protected function installSampleData(InputInterface $input, OutputInterface $output) |
||
457 | { |
||
458 | $magentoPackage = $this->config['magentoPackage']; /* @var $magentoPackage \Composer\Package\MemoryPackage */ |
||
459 | $extra = $magentoPackage->getExtra(); |
||
460 | if (!isset($extra['sample-data'])) { |
||
461 | return; |
||
462 | } |
||
463 | |||
464 | $dialog = $this->getHelperSet()->get('dialog'); |
||
465 | |||
466 | $installSampleData = ($input->getOption('installSampleData') !== null) ? $this->_parseBoolOption($input->getOption('installSampleData')) : $dialog->askConfirmation($output, '<question>Install sample data?</question> <comment>[y]</comment>: '); |
||
467 | |||
468 | if ($installSampleData) { |
||
469 | $filesystem = new Filesystem(); |
||
470 | |||
471 | foreach ($this->commandConfig['demo-data-packages'] as $demoPackageData) { |
||
472 | if ($demoPackageData['name'] == $extra['sample-data']) { |
||
473 | $package = $this->downloadByComposerConfig( |
||
474 | $input, |
||
475 | $output, |
||
476 | $demoPackageData, |
||
477 | $this->config['installationFolder'] . '/_temp_demo_data', |
||
478 | false |
||
479 | ); |
||
480 | |||
481 | $this->_fixComposerExtractionBug(); |
||
482 | |||
483 | $expandedFolder = $this->config['installationFolder'] |
||
484 | . '/_temp_demo_data/' |
||
485 | . str_replace(array('.tar.gz', '.tar.bz2', '.zip'), '', basename($package->getDistUrl())); |
||
486 | if (is_dir($expandedFolder)) { |
||
487 | $filesystem->recursiveCopy( |
||
488 | $expandedFolder, |
||
489 | $this->config['installationFolder'] |
||
490 | ); |
||
491 | $filesystem->recursiveRemoveDirectory($expandedFolder); |
||
492 | } |
||
493 | |||
494 | // Remove empty folder |
||
495 | View Code Duplication | if (is_dir($this->config['installationFolder'] . '/vendor/composer')) { |
|
496 | $filesystem->recursiveRemoveDirectory($this->config['installationFolder'] . '/vendor/composer'); |
||
497 | } |
||
498 | |||
499 | // Install sample data |
||
500 | $sampleDataSqlFile = glob($this->config['installationFolder'] . '/_temp_demo_data/magento_*sample_data*sql'); |
||
501 | $db = $this->config['db']; |
||
502 | /* @var $db PDO */ |
||
503 | if (isset($sampleDataSqlFile[0])) { |
||
504 | if (OperatingSystem::isProgramInstalled('mysql')) { |
||
505 | $exec = 'mysql ' |
||
506 | . '-h' . escapeshellarg(strval($this->config['db_host'])) |
||
507 | . ' ' |
||
508 | . '-u' . escapeshellarg(strval($this->config['db_user'])) |
||
509 | . ' ' |
||
510 | . ($this->config['db_port'] != '3306' ? '-P' . escapeshellarg($this->config['db_port']) . ' ' : '') |
||
511 | . (!strval($this->config['db_pass'] == '') ? '-p' . escapeshellarg($this->config['db_pass']) . ' ' : '') |
||
512 | . strval($this->config['db_name']) |
||
513 | . ' < ' |
||
514 | . escapeshellarg($sampleDataSqlFile[0]); |
||
515 | $output->writeln('<info>Importing <comment>' . $sampleDataSqlFile[0] . '</comment> with mysql cli client</info>'); |
||
516 | Exec::run($exec); |
||
517 | @unlink($sampleDataSqlFile[0]); |
||
518 | } else { |
||
519 | $output->writeln('<info>Importing <comment>' . $sampleDataSqlFile[0] . '</comment> with PDO driver</info>'); |
||
520 | // Fallback -> Try to install dump file by PDO driver |
||
521 | $dbUtils = new DatabaseUtils(); |
||
522 | $dbUtils->importSqlDump($db, $sampleDataSqlFile[0]); |
||
523 | } |
||
524 | } |
||
525 | } |
||
526 | } |
||
527 | |||
528 | View Code Duplication | if (is_dir($this->config['installationFolder'] . '/_temp_demo_data')) { |
|
529 | $filesystem->recursiveRemoveDirectory($this->config['installationFolder'] . '/_temp_demo_data'); |
||
530 | } |
||
531 | } |
||
532 | } |
||
533 | |||
534 | protected function _fixComposerExtractionBug() |
||
535 | { |
||
536 | $filesystem = new Filesystem(); |
||
537 | foreach (array('/_temp_demo_data/media' => '/media', '/_temp_demo_data/skin' => '/skin') as $wrong => $right) { |
||
538 | $wrongFolder = $this->config['installationFolder'] . $wrong; |
||
539 | $rightFolder = $this->config['installationFolder'] . $right; |
||
540 | if (is_dir($wrongFolder)) { |
||
541 | $filesystem->recursiveCopy( |
||
542 | $wrongFolder, |
||
543 | $rightFolder |
||
544 | ); |
||
545 | $filesystem->recursiveRemoveDirectory($wrongFolder); |
||
546 | } |
||
547 | } |
||
548 | } |
||
549 | |||
550 | /** |
||
551 | * Remove empty composer extraction folder |
||
552 | */ |
||
553 | protected function removeEmptyFolders() |
||
554 | { |
||
555 | if (is_dir(getcwd() . '/vendor')) { |
||
556 | $finder = new Finder(); |
||
557 | $finder->files()->depth(3)->in(getcwd() . '/vendor'); |
||
558 | if ($finder->count() == 0) { |
||
559 | $filesystem = new Filesystem(); |
||
560 | $filesystem->recursiveRemoveDirectory(getcwd() . '/vendor'); |
||
561 | } |
||
562 | } |
||
563 | } |
||
564 | |||
565 | /** |
||
566 | * @param InputInterface $input |
||
567 | * @param OutputInterface $output |
||
568 | * |
||
569 | * @return array |
||
570 | * @throws InvalidArgumentException parameter mismatch (e.g. base-url components like hostname) |
||
571 | * @throws RuntimeException |
||
572 | */ |
||
573 | protected function installMagento(InputInterface $input, OutputInterface $output) |
||
574 | { |
||
575 | $this->getApplication()->setAutoExit(false); |
||
576 | $dialog = $this->getHelperSet()->get('dialog'); |
||
577 | |||
578 | $defaults = $this->commandConfig['installation']['defaults']; |
||
579 | |||
580 | $useDefaultConfigParams = $this->_parseBoolOption($input->getOption('useDefaultConfigParams')); |
||
581 | |||
582 | $sessionSave = $useDefaultConfigParams ? $defaults['session_save'] : $dialog->ask( |
||
583 | $output, |
||
584 | '<question>Please enter the session save:</question> <comment>[' . $defaults['session_save'] . ']</comment>: ', |
||
585 | $defaults['session_save'] |
||
586 | ); |
||
587 | |||
588 | $adminFrontname = $useDefaultConfigParams ? $defaults['admin_frontname'] : $dialog->askAndValidate( |
||
589 | $output, |
||
590 | '<question>Please enter the admin frontname:</question> <comment>[' . $defaults['admin_frontname'] . ']</comment> ', |
||
591 | $this->notEmptyCallback, |
||
592 | false, |
||
593 | $defaults['admin_frontname'] |
||
594 | ); |
||
595 | |||
596 | $currency = $useDefaultConfigParams ? $defaults['currency'] : $dialog->askAndValidate( |
||
597 | $output, |
||
598 | '<question>Please enter the default currency code:</question> <comment>[' . $defaults['currency'] . ']</comment>: ', |
||
599 | $this->notEmptyCallback, |
||
600 | false, |
||
601 | $defaults['currency'] |
||
602 | ); |
||
603 | |||
604 | $locale = $useDefaultConfigParams ? $defaults['locale'] : $dialog->askAndValidate( |
||
605 | $output, |
||
606 | '<question>Please enter the locale code:</question> <comment>[' . $defaults['locale'] . ']</comment>: ', |
||
607 | $this->notEmptyCallback, |
||
608 | false, |
||
609 | $defaults['locale'] |
||
610 | ); |
||
611 | |||
612 | $timezone = $useDefaultConfigParams ? $defaults['timezone'] : $dialog->askAndValidate( |
||
613 | $output, |
||
614 | '<question>Please enter the timezone:</question> <comment>[' . $defaults['timezone'] . ']</comment>: ', |
||
615 | $this->notEmptyCallback, |
||
616 | false, |
||
617 | $defaults['timezone'] |
||
618 | ); |
||
619 | |||
620 | $adminUsername = $useDefaultConfigParams ? $defaults['admin_username'] : $dialog->askAndValidate( |
||
621 | $output, |
||
622 | '<question>Please enter the admin username:</question> <comment>[' . $defaults['admin_username'] . ']</comment>: ', |
||
623 | $this->notEmptyCallback, |
||
624 | false, |
||
625 | $defaults['admin_username'] |
||
626 | ); |
||
627 | |||
628 | $adminPassword = $useDefaultConfigParams ? $defaults['admin_password'] : $dialog->askAndValidate( |
||
629 | $output, |
||
630 | '<question>Please enter the admin password:</question> <comment>[' . $defaults['admin_password'] . ']</comment>: ', |
||
631 | $this->notEmptyCallback, |
||
632 | false, |
||
633 | $defaults['admin_password'] |
||
634 | ); |
||
635 | |||
636 | $adminFirstname = $useDefaultConfigParams ? $defaults['admin_firstname'] : $dialog->askAndValidate( |
||
637 | $output, |
||
638 | '<question>Please enter the admin\'s firstname:</question> <comment>[' . $defaults['admin_firstname'] . ']</comment>: ', |
||
639 | $this->notEmptyCallback, |
||
640 | false, |
||
641 | $defaults['admin_firstname'] |
||
642 | ); |
||
643 | |||
644 | $adminLastname = $useDefaultConfigParams ? $defaults['admin_lastname'] : $dialog->askAndValidate( |
||
645 | $output, |
||
646 | '<question>Please enter the admin\'s lastname:</question> <comment>[' . $defaults['admin_lastname'] . ']</comment>: ', |
||
647 | $this->notEmptyCallback, |
||
648 | false, |
||
649 | $defaults['admin_lastname'] |
||
650 | ); |
||
651 | |||
652 | $adminEmail = $useDefaultConfigParams ? $defaults['admin_email'] : $dialog->askAndValidate( |
||
653 | $output, |
||
654 | '<question>Please enter the admin\'s email:</question> <comment>[' . $defaults['admin_email'] . ']</comment>: ', |
||
655 | $this->notEmptyCallback, |
||
656 | false, |
||
657 | $defaults['admin_email'] |
||
658 | ); |
||
659 | |||
660 | $validateBaseUrl = function($input) { |
||
661 | if (!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $input)) { |
||
662 | throw new InvalidArgumentException('Please enter a valid URL'); |
||
663 | } |
||
664 | if (parse_url($input, \PHP_URL_HOST) == 'localhost') { |
||
665 | throw new InvalidArgumentException('localhost cause problems! Please use 127.0.0.1 or another hostname'); |
||
666 | } |
||
667 | return $input; |
||
668 | }; |
||
669 | |||
670 | $baseUrl = ($input->getOption('baseUrl') !== null) ? $input->getOption('baseUrl') : $dialog->askAndValidate( |
||
671 | $output, |
||
672 | '<question>Please enter the base url:</question> ', |
||
673 | $validateBaseUrl, |
||
674 | false |
||
675 | ); |
||
676 | $baseUrl = rtrim($baseUrl, '/') . '/'; // normalize baseUrl |
||
677 | |||
678 | /** |
||
679 | * Correct session save (common mistake) |
||
680 | */ |
||
681 | if ($sessionSave == 'file') { |
||
682 | $sessionSave = 'files'; |
||
683 | } |
||
684 | |||
685 | /** |
||
686 | * Try to create session folder |
||
687 | */ |
||
688 | $defaultSessionFolder = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'var/session'; |
||
689 | if ($sessionSave == 'files' && !is_dir($defaultSessionFolder)) { |
||
690 | @mkdir($defaultSessionFolder); |
||
691 | } |
||
692 | |||
693 | $dbHost = $this->config['db_host']; |
||
694 | if ($this->config['db_port'] != 3306) { |
||
695 | $dbHost .= ':' . $this->config['db_port']; |
||
696 | } |
||
697 | |||
698 | $argv = array( |
||
699 | 'license_agreement_accepted' => 'yes', |
||
700 | 'locale' => $locale, |
||
701 | 'timezone' => $timezone, |
||
702 | 'db_host' => $dbHost, |
||
703 | 'db_name' => $this->config['db_name'], |
||
704 | 'db_user' => $this->config['db_user'], |
||
705 | 'db_pass' => $this->config['db_pass'], |
||
706 | 'db_prefix' => $this->config['db_prefix'], |
||
707 | 'url' => $baseUrl, |
||
708 | 'use_rewrites' => 'yes', |
||
709 | 'use_secure' => 'no', |
||
710 | 'secure_base_url' => '', |
||
711 | 'use_secure_admin' => 'no', |
||
712 | 'admin_username' => $adminUsername, |
||
713 | 'admin_lastname' => $adminLastname, |
||
714 | 'admin_firstname' => $adminFirstname, |
||
715 | 'admin_email' => $adminEmail, |
||
716 | 'admin_password' => $adminPassword, |
||
717 | 'session_save' => $sessionSave, |
||
718 | 'admin_frontname' => $adminFrontname, /* magento 1 */ |
||
719 | 'backend_frontname' => $adminFrontname, /* magento 2 */ |
||
720 | 'default_currency' => $currency, |
||
721 | 'skip_url_validation' => 'yes', |
||
722 | ); |
||
723 | if ($useDefaultConfigParams) { |
||
724 | if (strlen($defaults['encryption_key']) > 0) { |
||
725 | $argv['encryption_key'] = $defaults['encryption_key']; |
||
726 | } |
||
727 | if (strlen($defaults['use_secure']) > 0) { |
||
728 | $argv['use_secure'] = $defaults['use_secure']; |
||
729 | $argv['secure_base_url'] = str_replace('http://', 'https://', $baseUrl); |
||
730 | } |
||
731 | if (strlen($defaults['use_rewrites']) > 0) { |
||
732 | $argv['use_rewrites'] = $defaults['use_rewrites']; |
||
733 | } |
||
734 | } |
||
735 | $installArgs = ''; |
||
736 | foreach ($argv as $argName => $argValue) { |
||
737 | $installArgs .= '--' . $argName . ' ' . escapeshellarg($argValue) . ' '; |
||
738 | } |
||
739 | |||
740 | $output->writeln('<info>Start installation process.</info>'); |
||
741 | |||
742 | if (OperatingSystem::isWindows()) { |
||
743 | $installCommand = 'php -f ' . escapeshellarg($this->getInstallScriptPath()) . ' -- ' . $installArgs; |
||
744 | } else { |
||
745 | $installCommand = '/usr/bin/env php -f ' . escapeshellarg($this->getInstallScriptPath()) . ' -- ' . $installArgs; |
||
0 ignored issues
–
show
|
|||
746 | } |
||
747 | $output->writeln('<comment>' . $installCommand . '</comment>'); |
||
748 | Exec::run($installCommand, $installationOutput, $returnStatus); |
||
749 | if ($returnStatus !== self::EXEC_STATUS_OK) { |
||
750 | $this->getApplication()->setAutoExit(true); |
||
751 | throw new RuntimeException('Installation failed.' . $installationOutput, 1); |
||
752 | } else { |
||
753 | $output->writeln('<info>Successfully installed Magento</info>'); |
||
754 | $encryptionKey = trim(substr($installationOutput, strpos($installationOutput, ':') + 1)); |
||
755 | $output->writeln('<comment>Encryption Key:</comment> <info>' . $encryptionKey . '</info>'); |
||
756 | } |
||
757 | |||
758 | $dialog = $this->getHelperSet()->get('dialog'); |
||
759 | |||
760 | /** |
||
761 | * Htaccess file |
||
762 | */ |
||
763 | if ($input->getOption('useDefaultConfigParams') == null || $input->getOption('replaceHtaccessFile') != null) { |
||
764 | $replaceHtaccessFile = false; |
||
765 | |||
766 | if ($this->_parseBoolOption($input->getOption('replaceHtaccessFile'))) { |
||
767 | $replaceHtaccessFile = true; |
||
768 | } elseif ($dialog->askConfirmation( |
||
769 | $output, |
||
770 | '<question>Write BaseURL to .htaccess file?</question> <comment>[n]</comment>: ', |
||
771 | false) |
||
772 | ) { |
||
773 | $replaceHtaccessFile = true; |
||
774 | } |
||
775 | |||
776 | if ($replaceHtaccessFile) { |
||
777 | $this->replaceHtaccessFile($baseUrl); |
||
778 | } |
||
779 | } |
||
780 | |||
781 | \chdir($this->config['installationFolder']); |
||
782 | $this->getApplication()->reinit(); |
||
783 | $output->writeln('<info>Reindex all after installation</info>'); |
||
784 | $this->getApplication()->run(new StringInput('index:reindex:all'), $output); |
||
785 | $this->getApplication()->run(new StringInput('sys:check'), $output); |
||
786 | $output->writeln('<info>Successfully installed magento</info>'); |
||
787 | } |
||
788 | |||
789 | /** |
||
790 | * Check if we have a magento 2 or 1 installation and return path to install.php |
||
791 | * |
||
792 | * @return string |
||
793 | */ |
||
794 | protected function getInstallScriptPath() |
||
795 | { |
||
796 | $magento1InstallScriptPath = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'install.php'; |
||
797 | $magento2InstallScriptPath = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'dev/shell/install.php'; |
||
798 | if (file_exists($magento2InstallScriptPath)) { |
||
799 | return $magento2InstallScriptPath; |
||
800 | } |
||
801 | |||
802 | return $magento1InstallScriptPath; |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * @param string $baseUrl |
||
807 | */ |
||
808 | protected function replaceHtaccessFile($baseUrl) |
||
809 | { |
||
810 | $content = file_get_contents($this->config['installationFolder'] . DIRECTORY_SEPARATOR . '.htaccess'); |
||
811 | copy($this->config['installationFolder'] . DIRECTORY_SEPARATOR . '.htaccess', $this->config['installationFolder'] . DIRECTORY_SEPARATOR . '.htaccess.dist'); |
||
812 | $content = str_replace('#RewriteBase /magento/', 'RewriteBase ' . parse_url($baseUrl, PHP_URL_PATH), $content); |
||
813 | file_put_contents($this->config['installationFolder'] . DIRECTORY_SEPARATOR . '.htaccess', $content); |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * @param OutputInterface $output |
||
818 | */ |
||
819 | protected function setDirectoryPermissions($output) |
||
820 | { |
||
821 | try { |
||
822 | $varFolder = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'var'; |
||
823 | if (!is_dir($varFolder)) { |
||
824 | @mkdir($varFolder); |
||
825 | } |
||
826 | @chmod($varFolder, 0777); |
||
827 | |||
828 | $varCacheFolder = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'var/cache'; |
||
829 | if (!is_dir($varCacheFolder)) { |
||
830 | @mkdir($varCacheFolder); |
||
831 | } |
||
832 | @chmod($varCacheFolder, 0777); |
||
833 | |||
834 | $mediaFolder = $this->config['installationFolder'] . DIRECTORY_SEPARATOR . 'media'; |
||
835 | if (!is_dir($mediaFolder)) { |
||
836 | @mkdir($mediaFolder); |
||
837 | } |
||
838 | @chmod($mediaFolder, 0777); |
||
839 | |||
840 | $finder = Finder::create(); |
||
841 | $finder->directories() |
||
842 | ->ignoreUnreadableDirs(true) |
||
843 | ->in(array($varFolder, $mediaFolder)); |
||
844 | foreach ($finder as $dir) { |
||
845 | @chmod($dir->getRealpath(), 0777); |
||
846 | } |
||
847 | } catch (Exception $e) { |
||
848 | $output->writeln('<error>' . $e->getMessage() . '</error>'); |
||
849 | } |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * @return array |
||
854 | */ |
||
855 | public function getCliArguments() |
||
856 | { |
||
857 | if ($this->_argv === null) { |
||
858 | $this->_argv = $_SERVER['argv']; |
||
859 | } |
||
860 | |||
861 | return $this->_argv; |
||
862 | } |
||
863 | |||
864 | /** |
||
865 | * @param array $args |
||
866 | */ |
||
867 | public function setCliArguments($args) |
||
868 | { |
||
869 | $this->_argv = $args; |
||
870 | } |
||
871 | } |
||
872 |
Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.