Skip to content
Snippets Groups Projects
Commit e6e3c83d authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #3093993 by heddn, andypost, greg.1.anderson: Add options to handle database updates

parent 62c2f724
No related branches found
No related tags found
No related merge requests found
Showing
with 832 additions and 10 deletions
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
*/ */
use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface; use Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManagerInterface;
use Drupal\update\UpdateManagerInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\update\UpdateManagerInterface;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
/** /**
* Implements hook_page_top(). * Implements hook_page_top().
...@@ -91,20 +93,35 @@ function automatic_updates_cron() { ...@@ -91,20 +93,35 @@ function automatic_updates_cron() {
$not_recommended_version = $projects['drupal']['status'] !== UpdateManagerInterface::CURRENT; $not_recommended_version = $projects['drupal']['status'] !== UpdateManagerInterface::CURRENT;
$security_update = in_array($projects['drupal']['status'], [UpdateManagerInterface::NOT_SECURE, UpdateManagerInterface::REVOKED], TRUE); $security_update = in_array($projects['drupal']['status'], [UpdateManagerInterface::NOT_SECURE, UpdateManagerInterface::REVOKED], TRUE);
$recommended_release = isset($projects['drupal']['releases'][$projects['drupal']['recommended']]) ? $projects['drupal']['releases'][$projects['drupal']['recommended']] : NULL; $recommended_release = isset($projects['drupal']['releases'][$projects['drupal']['recommended']]) ? $projects['drupal']['releases'][$projects['drupal']['recommended']] : NULL;
$major_upgrade = isset($recommended_release['version_major']) ? $recommended_release['version_major'] !== $projects['drupal']['existing_major'] : TRUE; $existing_minor_version = explode('.', \Drupal::VERSION, -1);
// Don't automatically update major version bumps or a dev version of core. $recommended_minor_version = explode('.', $recommended_release['version'], -1);
if (!$major_upgrade && $config->get('enable_cron_security_updates')) { $major_upgrade = $existing_minor_version !== $recommended_minor_version;
if ($not_recommended_version && $security_update) { if ($major_upgrade) {
foreach (range(1, 30) as $point_version) {
$potential_version = implode('.', array_merge($existing_minor_version, (array) $point_version));
if (isset($available['drupal']['releases'][$potential_version])) {
$recommended_release = $available['drupal']['releases'][$potential_version];
}
else {
break;
}
}
}
// Don't automatically update major version bumps or from/to same version.
if ($not_recommended_version && $projects['drupal']['existing_version'] !== $recommended_release['version']) {
if ($config->get('enable_cron_security_updates')) {
if ($security_update) {
/** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */
$updater = \Drupal::service('automatic_updates.update');
$updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']);
}
}
else {
/** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */ /** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */
$updater = \Drupal::service('automatic_updates.update'); $updater = \Drupal::service('automatic_updates.update');
$updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']); $updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']);
} }
} }
elseif (!$major_upgrade && $not_recommended_version) {
/** @var \Drupal\automatic_updates\Services\UpdateInterface $updater */
$updater = \Drupal::service('automatic_updates.update');
$updater->update('drupal', 'core', \Drupal::VERSION, $recommended_release['version']);
}
} }
/** @var \Drupal\automatic_updates\Services\NotifyInterface $notify */ /** @var \Drupal\automatic_updates\Services\NotifyInterface $notify */
...@@ -141,3 +158,30 @@ function automatic_updates_mail($key, &$message, $params) { ...@@ -141,3 +158,30 @@ function automatic_updates_mail($key, &$message, $params) {
$message['subject'] = $params['subject']; $message['subject'] = $params['subject'];
$message['body'][] = $renderer->render($params['body']); $message['body'][] = $renderer->render($params['body']);
} }
/**
* Helper method to execute console command.
*
* @param string $command_argument
* The command argument.
*
* @return \Symfony\Component\Process\Process
* The console command process.
*/
function automatic_updates_console_command($command_argument) {
$module_path = drupal_get_path('module', 'automatic_updates');
$command = [
(new PhpExecutableFinder())->find(),
$module_path . '/scripts/automatic_update_tools',
$command_argument,
'--script-filename',
\Drupal::request()->server->get('SCRIPT_FILENAME'),
'--base-url',
\Drupal::request()->getBaseUrl(),
'--base-path',
\Drupal::request()->getBasePath(),
];
$process = new Process($command, (string) \Drupal::root(), NULL, NULL, NULL);
$process->run();
return $process;
}
...@@ -43,6 +43,9 @@ services: ...@@ -43,6 +43,9 @@ services:
- '@file_system' - '@file_system'
- '@http_client' - '@http_client'
- '@app.root' - '@app.root'
plugin.manager.database_update_handler:
class: Drupal\automatic_updates\DatabaseUpdateHandlerPluginManager
parent: default_plugin_manager
automatic_updates.readiness_checker: automatic_updates.readiness_checker:
class: Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManager class: Drupal\automatic_updates\ReadinessChecker\ReadinessCheckerManager
...@@ -92,6 +95,8 @@ services: ...@@ -92,6 +95,8 @@ services:
- { name: readiness_checker, category: warning} - { name: readiness_checker, category: warning}
automatic_updates.pending_db_updates: automatic_updates.pending_db_updates:
class: Drupal\automatic_updates\ReadinessChecker\PendingDbUpdates class: Drupal\automatic_updates\ReadinessChecker\PendingDbUpdates
arguments:
- '@update.post_update_registry'
tags: tags:
- { name: readiness_checker, category: error} - { name: readiness_checker, category: error}
automatic_updates.missing_project_info: automatic_updates.missing_project_info:
......
...@@ -8,3 +8,7 @@ ignored_paths: "modules/*\nthemes/*\nprofiles/*" ...@@ -8,3 +8,7 @@ ignored_paths: "modules/*\nthemes/*\nprofiles/*"
download_uri: 'https://www.drupal.org/in-place-updates' download_uri: 'https://www.drupal.org/in-place-updates'
enable_cron_updates: false enable_cron_updates: false
enable_cron_security_updates: false enable_cron_security_updates: false
database_update_handling:
- maintenance_mode_activate
- execute_updates
- maintenance_mode_disactivate
...@@ -32,3 +32,9 @@ automatic_updates.settings: ...@@ -32,3 +32,9 @@ automatic_updates.settings:
enable_cron_security_updates: enable_cron_security_updates:
type: boolean type: boolean
label: 'Enable automatic updates for security releases via cron' label: 'Enable automatic updates for security releases via cron'
database_update_handling:
type: sequence
label: 'Database update handling'
sequence:
type: string
label: 'Tagged service to handle database updates'
#!/usr/bin/env php
<?php
/**
* @file
* Provides helper commands for automatic updates.
*
* This must be a separate application so class caches aren't an issue during
* in place updates.
*/
use Drupal\automatic_updates\Command\CacheRebuild;
use Drupal\automatic_updates\Command\DatabaseUpdate;
use Drupal\automatic_updates\Command\DatabaseUpdateStatus;
use Symfony\Component\Console\Application;
if (PHP_SAPI !== 'cli') {
return;
}
// Set up autoloader
$loader = false;
if (file_exists($autoloader = __DIR__ . '/../../../../autoload.php')
|| file_exists($autoloader = __DIR__ . '/../../../../../autoload.php')
|| file_exists($autoloader = __DIR__ . '/../../../autoload.php')
) {
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require_once $autoloader;
// Drupal's autoloader doesn't bootstrap this module's classes yet. Do so
// manually.
$loader->addPsr4('Drupal\\automatic_updates\\', __DIR__ . '/../src');
}
else {
throw new \RuntimeException('Could not locate autoload.php; __DIR__ is ' . __DIR__);
}
$application = new Application('automatic_update_tools', 'stable');
$application->add(new CacheRebuild($loader));
$application->add(new DatabaseUpdate($loader));
$application->add(new DatabaseUpdateStatus($loader));
$application->run();
<?php
namespace Drupal\automatic_updates\Annotation;
use Drupal\Component\Annotation\Plugin;
/**
* Defines a DatabaseUpdateHandler annotation object.
*
* Plugin Namespace: Plugin\DatabaseUpdateHandler.
*
* For a working example, see
* \Drupal\automatic_updates\Plugin\DatabaseUpdateHandler\MaintenanceMode.
*
* @see \Drupal\automatic_updates\DatabaseUpdateHandlerInterface
* @see \Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase
* @see \Drupal\automatic_updates\DatabaseUpdateHandlerPluginManager
* @see hook_database_update_handler_plugin_info_alter()
* @see plugin_api
*
* @Annotation
*/
final class DatabaseUpdateHandler extends Plugin {
/**
* The ID of the handler, should match the service name.
*
* @var string
*/
public $id;
/**
* The name of the handler.
*
* @var string
*/
public $label;
}
<?php
namespace Drupal\automatic_updates\Command;
use Drupal\Core\DrupalKernel;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Base command class.
*/
class BaseCommand extends Command {
/**
* The class loader.
*
* @var object
*/
protected $classLoader;
/**
* Constructs a new InstallCommand command.
*
* @param object $class_loader
* The class loader.
*/
public function __construct($class_loader) {
$this->classLoader = $class_loader;
parent::__construct();
}
/**
* {@inheritdoc}
*/
protected function configure() {
parent::configure();
$this->addOption('script-filename', NULL, InputOption::VALUE_REQUIRED, 'The script filename')
->addOption('base-url', NULL, InputOption::VALUE_REQUIRED, 'The base URL, i.e. http://example.com/index.php')
->addOption('base-path', NULL, InputOption::VALUE_REQUIRED, 'The base path, i.e. http://example.com');
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$this->bootstrapDrupal($input);
}
/**
* Bootstrap Drupal.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* The input.
*/
protected function bootstrapDrupal(InputInterface $input) {
$kernel = new DrupalKernel('prod', $this->classLoader);
$script_filename = $input->getOption('script-filename');
$base_url = $input->getOption('base-url');
$base_path = $input->getOption('base-path');
$server = [
'SCRIPT_FILENAME' => $script_filename,
'SCRIPT_NAME' => $base_url,
];
$request = Request::create($base_path, 'GET', [], [], [], $server);
$kernel->handle($request);
}
}
<?php
namespace Drupal\automatic_updates\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Cache rebuild command.
*/
class CacheRebuild extends BaseCommand {
/**
* {@inheritdoc}
*/
protected function configure() {
parent::configure();
$this->setName('cache:rebuild')
->setAliases(['cr, rebuild'])
->setDescription('Rebuild a Drupal site and clear all its caches.');
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
parent::execute($input, $output);
drupal_flush_all_caches();
$output->writeln('Cache rebuild complete.');
}
}
<?php
namespace Drupal\automatic_updates\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Database update command.
*/
class DatabaseUpdate extends BaseCommand {
/**
* {@inheritdoc}
*/
protected function configure() {
parent::configure();
$this->setName('updatedb')
->setDescription('Apply any database updates required (as with running update.php).')
->setAliases(['updb']);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
parent::execute($input, $output);
$pending_updates = \Drupal::service('automatic_updates.pending_db_updates')
->run();
if ($pending_updates) {
$output->writeln('Started database updates.');
$this->executeDatabaseUpdates();
$output->writeln('Finished database updates.');
}
else {
$output->writeln('No database updates required.');
}
}
/**
* Execute all outstanding database updates.
*/
protected function executeDatabaseUpdates() {
require_once DRUPAL_ROOT . '/core/includes/install.inc';
require_once DRUPAL_ROOT . '/core/includes/update.inc';
$logger = \Drupal::logger('automatic_updates');
drupal_load_updates();
$start = $dependency_map = $operations = [];
foreach (update_get_update_list() as $module => $update) {
$start[$module] = $update['start'];
}
$updates = update_resolve_dependencies($start);
foreach ($updates as $function => $update) {
$dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : [];
}
foreach ($updates as $function => $update) {
if ($update['allowed']) {
// Set the installed version of each module so updates will start at the
// correct place. (The updates are already sorted, so we can simply base
// this on the first one we come across in the above foreach loop.)
if (isset($start[$update['module']])) {
drupal_set_installed_schema_version($update['module'], $update['number'] - 1);
unset($start[$update['module']]);
}
$this->executeDatabaseUpdate('update_do_one', [
$update['module'],
$update['number'],
$dependency_map[$function],
]);
}
}
$post_updates = \Drupal::service('update.post_update_registry')->getPendingUpdateFunctions();
if ($post_updates) {
// Now we rebuild all caches and after that execute hook_post_update().
$logger->info('Starting cache clear pre-step of database update.');
automatic_updates_console_command('cache:rebuild');
$logger->info('Finished cache clear pre-step of database update.');
foreach ($post_updates as $function) {
$this->executeDatabaseUpdate('update_invoke_post_update', [$function]);
}
}
}
/**
* Execute a single database update.
*
* @param callable $invoker
* Callable update invoker.
* @param array $args
* The arguments to pass to the invoker.
*/
protected function executeDatabaseUpdate(callable $invoker, array $args) {
\Drupal::logger('automatic_updates')->notice('Database update running with arguments "@arguments"', ['@arguments' => print_r($args, TRUE)]);
$context = [
'sandbox' => [],
];
call_user_func_array($invoker, array_merge($args, [&$context]));
\Drupal::logger('automatic_updates')->notice('Database update finished with arguments "@arguments"', ['@arguments' => print_r($args, TRUE)]);
}
}
<?php
namespace Drupal\automatic_updates\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Database update status command.
*/
class DatabaseUpdateStatus extends BaseCommand {
/**
* {@inheritdoc}
*/
protected function configure() {
parent::configure();
$this->setName('updatedb-status')
->setDescription('Apply any database updates required (as with running update.php).')
->setAliases(['updbst', 'updatedb:status']);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
parent::execute($input, $output);
$pending_updates = \Drupal::service('automatic_updates.pending_db_updates')
->run();
$output->writeln($pending_updates);
}
}
<?php
namespace Drupal\automatic_updates;
/**
* Interface for database_update_handler plugins.
*/
interface DatabaseUpdateHandlerInterface {
/**
* Returns the translated plugin label.
*
* @return string
* The translated title.
*/
public function label();
/**
* Handle database updates.
*
* @return bool
* TRUE if database update was handled successfully, FALSE otherwise.
*/
public function execute();
}
<?php
namespace Drupal\automatic_updates;
use Drupal\Component\Plugin\PluginBase;
/**
* Base class for database_update_handler plugins.
*/
abstract class DatabaseUpdateHandlerPluginBase extends PluginBase implements DatabaseUpdateHandlerInterface {
/**
* {@inheritdoc}
*/
public function label() {
return $this->pluginDefinition['label'];
}
}
<?php
namespace Drupal\automatic_updates;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* DatabaseUpdateHandler plugin manager.
*/
class DatabaseUpdateHandlerPluginManager extends DefaultPluginManager {
/**
* Constructs DatabaseUpdateHandlerPluginManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct(
'Plugin/DatabaseUpdateHandler',
$namespaces,
$module_handler,
'Drupal\automatic_updates\DatabaseUpdateHandlerInterface',
'Drupal\automatic_updates\Annotation\DatabaseUpdateHandler'
);
$this->alterInfo('database_update_handler_info');
$this->setCacheBackend($cache_backend, 'database_update_handler_plugins');
}
}
...@@ -40,6 +40,13 @@ class SettingsForm extends ConfigFormBase { ...@@ -40,6 +40,13 @@ class SettingsForm extends ConfigFormBase {
*/ */
protected $updateManager; protected $updateManager;
/**
* The update processor.
*
* @var \Drupal\update\UpdateProcessorInterface
*/
protected $updateProcessor;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -49,6 +56,7 @@ class SettingsForm extends ConfigFormBase { ...@@ -49,6 +56,7 @@ class SettingsForm extends ConfigFormBase {
$instance->dateFormatter = $container->get('date.formatter'); $instance->dateFormatter = $container->get('date.formatter');
$instance->drupalRoot = (string) $container->get('app.root'); $instance->drupalRoot = (string) $container->get('app.root');
$instance->updateManager = $container->get('update.manager'); $instance->updateManager = $container->get('update.manager');
$instance->updateProcessor = $container->get('update.processor');
return $instance; return $instance;
} }
...@@ -126,6 +134,7 @@ class SettingsForm extends ConfigFormBase { ...@@ -126,6 +134,7 @@ class SettingsForm extends ConfigFormBase {
]; ];
$this->updateManager->refreshUpdateData(); $this->updateManager->refreshUpdateData();
$this->updateProcessor->fetchData();
$available = update_get_available(TRUE); $available = update_get_available(TRUE);
$projects = update_calculate_project_data($available); $projects = update_calculate_project_data($available);
$not_recommended_version = $projects['drupal']['status'] !== UpdateManagerInterface::CURRENT; $not_recommended_version = $projects['drupal']['status'] !== UpdateManagerInterface::CURRENT;
......
<?php
namespace Drupal\automatic_updates\Plugin\DatabaseUpdateHandler;
use Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Execute database updates.
*
* @DatabaseUpdateHandler(
* id = "execute_updates",
* label = "Execute database updates",
* )
*/
class ExecuteUpdates extends DatabaseUpdateHandlerPluginBase implements ContainerFactoryPluginInterface {
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new maintenance mode service.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('logger.channel.automatic_updates')
);
}
/**
* {@inheritdoc}
*/
public function execute() {
$process = automatic_updates_console_command('updatedb');
if ($errors = $process->getErrorOutput()) {
$this->logger->error($errors);
return FALSE;
}
return TRUE;
}
}
<?php
namespace Drupal\automatic_updates\Plugin\DatabaseUpdateHandler;
use Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Ignore database updates.
*
* @DatabaseUpdateHandler(
* id = "ignore_updates",
* label = "Ignore database updates",
* )
*/
class IgnoreUpdates extends DatabaseUpdateHandlerPluginBase implements ContainerFactoryPluginInterface {
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new maintenance mode service.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('logger.channel.automatic_updates')
);
}
/**
* {@inheritdoc}
*/
public function execute() {
$this->logger->notice('Database updates ignored.');
// Ignore the updates and hope for the best.
return TRUE;
}
}
<?php
namespace Drupal\automatic_updates\Plugin\DatabaseUpdateHandler;
use Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\State\StateInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Put site into maintenance mode if there are database updates.
*
* @DatabaseUpdateHandler(
* id = "maintenance_mode_activate",
* label = "Put site into maintenance mode",
* )
*/
class MaintenanceModeActivate extends DatabaseUpdateHandlerPluginBase implements ContainerFactoryPluginInterface {
/**
* The state.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new maintenance mode service.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\State\StateInterface $state
* The state.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, StateInterface $state, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->state = $state;
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('state'),
$container->get('logger.channel.automatic_updates')
);
}
/**
* {@inheritdoc}
*/
public function execute() {
$this->logger->notice('Maintenance mode activated.');
$this->state->set('system.maintenance_mode', TRUE);
return TRUE;
}
}
<?php
namespace Drupal\automatic_updates\Plugin\DatabaseUpdateHandler;
use Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\State\StateInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Remove site from maintenance mode.
*
* @DatabaseUpdateHandler(
* id = "maintenance_mode_disactivate",
* label = "Remove site from maintenance mode",
* )
*/
class MaintenanceModeDisactivate extends DatabaseUpdateHandlerPluginBase implements ContainerFactoryPluginInterface {
/**
* The state.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new maintenance mode service.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\State\StateInterface $state
* The state.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, StateInterface $state, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->state = $state;
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('state'),
$container->get('logger.channel.automatic_updates')
);
}
/**
* {@inheritdoc}
*/
public function execute() {
$this->logger->notice('Maintenance mode dis-activated.');
$this->state->set('system.maintenance_mode', FALSE);
return TRUE;
}
}
<?php
namespace Drupal\automatic_updates\Plugin\DatabaseUpdateHandler;
use Drupal\automatic_updates\DatabaseUpdateHandlerPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Rollback database updates.
*
* @DatabaseUpdateHandler(
* id = "rollback",
* label = "Rollback database updates",
* )
*/
class RollbackUpdate extends DatabaseUpdateHandlerPluginBase implements ContainerFactoryPluginInterface {
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new maintenance mode service.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('logger.channel.automatic_updates')
);
}
/**
* {@inheritdoc}
*/
public function execute() {
$this->logger->notice('Rollback initiated due to database updates.');
// Simply rollback the update by returning FALSE.
return FALSE;
}
}
...@@ -16,6 +16,8 @@ class MinimumPhpVersion extends SupportedPhpVersion { ...@@ -16,6 +16,8 @@ class MinimumPhpVersion extends SupportedPhpVersion {
*/ */
protected function getUnsupportedVersionConstraint() { protected function getUnsupportedVersionConstraint() {
$parser = new VersionParser(); $parser = new VersionParser();
// Constant was introduced in 8.7.0-beta1, back fill for full 8.7 support.
defined('DRUPAL_MINIMUM_SUPPORTED_PHP') or define('DRUPAL_MINIMUM_SUPPORTED_PHP', '7.0.8');
return $parser->parseConstraints('<' . DRUPAL_MINIMUM_SUPPORTED_PHP); return $parser->parseConstraints('<' . DRUPAL_MINIMUM_SUPPORTED_PHP);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment