. * --------------------------------------------------------------------- */ namespace Glpi\Console\Database; if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } use Glpi\Console\AbstractCommand; use Glpi\Console\Command\ForceNoPluginsOptionCommandInterface; use Migration; use Session; use Update; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; class UpdateCommand extends AbstractCommand implements ForceNoPluginsOptionCommandInterface { /** * Error code returned when trying to update from an unstable version. * * @var integer */ const ERROR_NO_UNSTABLE_UPDATE = 1; /** * Error code returned when security key file is missing. * * @var integer */ const ERROR_MISSING_SECURITY_KEY_FILE = 2; protected function configure() { parent::configure(); $this->setName('glpi:database:update'); $this->setAliases(['db:update']); $this->setDescription(__('Update database schema to new version')); $this->addOption( 'allow-unstable', 'u', InputOption::VALUE_NONE, __('Allow update to an unstable version') ); $this->addOption( 'force', 'f', InputOption::VALUE_NONE, __('Force execution of update from v-1 version of GLPI even if schema did not changed') ); } protected function initialize(InputInterface $input, OutputInterface $output) { parent::initialize($input, $output); $this->outputWarningOnMissingOptionnalRequirements(); $this->db->disableTableCaching(); } protected function execute(InputInterface $input, OutputInterface $output) { $allow_unstable = $input->getOption('allow-unstable'); $force = $input->getOption('force'); $no_interaction = $input->getOption('no-interaction'); // Base symfony/console option $update = new Update($this->db); // Initialize entities $_SESSION['glpidefault_entity'] = 0; Session::initEntityProfiles(2); Session::changeProfile(4); // Display current/future state informations $currents = $update->getCurrents(); $current_version = $currents['version']; $current_db_version = $currents['dbversion']; global $migration; // Migration scripts are using global migrations $migration = new Migration(GLPI_SCHEMA_VERSION); $migration->setOutputHandler($output); $update->setMigration($migration); $informations = new Table($output); $informations->setHeaders(['', __('Current'), _n('Target', 'Targets', 1)]); $informations->addRow([__('Database host'), $this->db->dbhost, '']); $informations->addRow([__('Database name'), $this->db->dbdefault, '']); $informations->addRow([__('Database user'), $this->db->dbuser, '']); $informations->addRow([__('GLPI version'), $current_version, GLPI_VERSION]); $informations->addRow([__('GLPI database version'), $current_db_version, GLPI_SCHEMA_VERSION]); $informations->render(); if (defined('GLPI_PREVER')) { // Prevent unstable update unless explicitly asked if (!$allow_unstable && version_compare($current_db_version, GLPI_SCHEMA_VERSION, 'ne')) { $output->writeln( sprintf( '' . __('%s is not a stable release. Please upgrade manually or add --allow-unstable option.') . '', GLPI_SCHEMA_VERSION ), OutputInterface::VERBOSITY_QUIET ); return self::ERROR_NO_UNSTABLE_UPDATE; } } if (version_compare($current_db_version, GLPI_SCHEMA_VERSION, 'eq') && !$force) { $output->writeln('' . __('No migration needed.') . ''); return 0; } if ($update->isExpectedSecurityKeyFileMissing()) { $output->writeln( sprintf( '' . __('The key file "%s" used to encrypt/decrypt sensitive data is missing. You should retrieve it from your previous installation or encrypted data will be unreadable.') . '', $update->getExpectedSecurityKeyFilePath() ), OutputInterface::VERBOSITY_QUIET ); if ($no_interaction) { return self::ERROR_MISSING_SECURITY_KEY_FILE; } } if (!$no_interaction) { // Ask for confirmation (unless --no-interaction) /** @var \Symfony\Component\Console\Helper\QuestionHelper $question_helper */ $question_helper = $this->getHelper('question'); $run = $question_helper->ask( $input, $output, new ConfirmationQuestion(__('Do you want to continue ?') . ' [Yes/no]', true) ); if (!$run) { $output->writeln( '' . __('Update aborted.') . '', OutputInterface::VERBOSITY_VERBOSE ); return 0; } } $update->doUpdates($current_version); if (version_compare($current_db_version, GLPI_SCHEMA_VERSION, 'ne')) { // Migration is considered as done as Update class has the responsibility // to run updates if schema has changed (even for "pre-versions". $output->writeln('' . __('Migration done.') . ''); } else if ($force) { // Replay last update script even if there is no schema change. // It can be used in dev environment when update script has been updated/fixed. include_once(GLPI_ROOT . '/install/update_951_952.php'); update951to952(); $output->writeln('' . __('Last migration replayed.') . ''); } return 0; // Success } public function getNoPluginsOptionValue() { return true; } }