Newer
Older
<?php
namespace Drupal\automatic_updates\Form;
use Drupal\automatic_updates\BatchProcessor;
use Drupal\automatic_updates\Updater;

Adam G-H
committed
use Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator;
use Drupal\Core\Batch\BatchBuilder;

Adam G-H
committed
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\package_manager\Exception\StageOwnershipException;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a form to commit staged updates.
*
* @internal
* Form classes are internal.
*/
class UpdateReady extends FormBase {
/**
* The updater service.
*
* @var \Drupal\automatic_updates\Updater
*/
protected $updater;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;

Adam G-H
committed
/**
* The module list service.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleList;
/**
* The staged database update validator service.
*
* @var \Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator
*/
protected $stagedDatabaseUpdateValidator;
/**
* Constructs a new UpdateReady object.
*
* @param \Drupal\automatic_updates\Updater $updater
* The updater service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.

Adam G-H
committed
* @param \Drupal\Core\Extension\ModuleExtensionList $module_list
* The module list service.
* @param \Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator $staged_database_update_validator
* The staged database update validator service.

Adam G-H
committed
public function __construct(Updater $updater, MessengerInterface $messenger, StateInterface $state, ModuleExtensionList $module_list, StagedDatabaseUpdateValidator $staged_database_update_validator) {
$this->updater = $updater;
$this->setMessenger($messenger);
$this->state = $state;

Adam G-H
committed
$this->moduleList = $module_list;
$this->stagedDatabaseUpdateValidator = $staged_database_update_validator;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'automatic_updates_update_ready_form';
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('automatic_updates.updater'),
$container->get('messenger'),

Adam G-H
committed
$container->get('state'),
$container->get('extension.list.module'),
$container->get('automatic_updates.validator.staged_database_updates')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, string $stage_id = NULL) {
try {
$this->updater->claim($stage_id);
}
catch (StageOwnershipException $e) {
$this->messenger()->addError($this->t('Cannot continue the update because another Composer operation is currently in progress.'));

Ted Bowman
committed
return $form;
}

Adam G-H
committed
// Don't check for pending database updates if the form has been submitted,
// because we don't want to store the warning in the messenger during form
// submit.
if (!$form_state->getUserInput()) {
// If there are any installed modules with database updates in the staging
// area, warn the user that they might be sent to update.php once the
// staged changes have been applied.
$pending_updates = $this->getModulesWithStagedDatabaseUpdates();
if ($pending_updates) {
$this->messenger()->addWarning($this->t('Possible database updates were detected in the following modules; you may be redirected to the database update page in order to complete the update process.'));
foreach ($pending_updates as $info) {
$this->messenger()->addWarning($info['name']);
}
}
}
$form['stage_id'] = [
'#type' => 'value',
'#value' => $stage_id,
];
$form['backup'] = [
'#prefix' => '<strong>',
'#markup' => $this->t('Back up your database and site before you continue. <a href=":backup_url">Learn how</a>.', [':backup_url' => 'https://www.drupal.org/node/22281']),
'#suffix' => '</strong>',
];
$form['maintenance_mode'] = [
'#title' => $this->t('Perform updates with site in maintenance mode (strongly recommended)'),
'#type' => 'checkbox',
'#default_value' => TRUE,
];
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Continue'),
];
return $form;
}

Adam G-H
committed
/**
* Returns info for all installed modules that have staged database updates.
*
* @return array[]
* The info arrays for the modules which have staged database updates, keyed
* by module machine name.
*/
protected function getModulesWithStagedDatabaseUpdates(): array {
$filter = function (string $name): bool {
return $this->stagedDatabaseUpdateValidator->hasStagedUpdates($this->updater, $this->moduleList->get($name));
};
return array_filter($this->moduleList->getAllInstalledInfo(), $filter, ARRAY_FILTER_USE_KEY);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$session = $this->getRequest()->getSession();
// Store maintenance_mode setting so we can restore it when done.
$session->set('maintenance_mode', $this->state->get('system.maintenance_mode'));
if ($form_state->getValue('maintenance_mode') === TRUE) {
$this->state->set('system.maintenance_mode', TRUE);
// @todo unset after updater. After db update?
}
$stage_id = $form_state->getValue('stage_id');
$batch = (new BatchBuilder())
->setTitle($this->t('Apply updates'))
->setInitMessage($this->t('Preparing to apply updates'))
->addOperation([BatchProcessor::class, 'commit'], [$stage_id])
->addOperation([BatchProcessor::class, 'clean'], [$stage_id])
->setFinishCallback([BatchProcessor::class, 'finishCommit'])
->toArray();
batch_set($batch);