Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 392 |
DbUpdateController | |
0.00% |
0 / 1 |
|
0.00% |
0 / 12 |
4290 | |
0.00% |
0 / 392 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 9 |
|||
create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 11 |
|||
handle | |
0.00% |
0 / 1 |
132 | |
0.00% |
0 / 45 |
|||
info | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 28 |
|||
selection | |
0.00% |
0 / 1 |
272 | |
0.00% |
0 / 110 |
|||
results | |
0.00% |
0 / 1 |
306 | |
0.00% |
0 / 98 |
|||
requirements | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 10 |
|||
updateTasksList | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 14 |
|||
triggerBatch | |
0.00% |
0 / 1 |
90 | |
0.00% |
0 / 38 |
|||
batchFinished | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
helpfulLinks | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 13 |
|||
getModuleUpdates | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\system\Controller\DbUpdateController. | |
*/ | |
namespace Drupal\system\Controller; | |
use Drupal\Core\Cache\CacheBackendInterface; | |
use Drupal\Core\Controller\ControllerBase; | |
use Drupal\Core\Extension\ModuleHandlerInterface; | |
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface; | |
use Drupal\Core\Render\BareHtmlPageRendererInterface; | |
use Drupal\Core\Session\AccountInterface; | |
use Drupal\Core\Site\Settings; | |
use Drupal\Core\State\StateInterface; | |
use Drupal\Core\Update\UpdateRegistry; | |
use Drupal\Core\Url; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\HttpFoundation\Request; | |
/** | |
* Controller routines for database update routes. | |
*/ | |
class DbUpdateController extends ControllerBase { | |
/** | |
* The keyvalue expirable factory. | |
* | |
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface | |
*/ | |
protected $keyValueExpirableFactory; | |
/** | |
* A cache backend interface. | |
* | |
* @var \Drupal\Core\Cache\CacheBackendInterface | |
*/ | |
protected $cache; | |
/** | |
* The state service. | |
* | |
* @var \Drupal\Core\State\StateInterface | |
*/ | |
protected $state; | |
/** | |
* The module handler. | |
* | |
* @var \Drupal\Core\Extension\ModuleHandlerInterface | |
*/ | |
protected $moduleHandler; | |
/** | |
* The current user. | |
* | |
* @var \Drupal\Core\Session\AccountInterface | |
*/ | |
protected $account; | |
/** | |
* The bare HTML page renderer. | |
* | |
* @var \Drupal\Core\Render\BareHtmlPageRendererInterface | |
*/ | |
protected $bareHtmlPageRenderer; | |
/** | |
* The app root. | |
* | |
* @var string | |
*/ | |
protected $root; | |
/** | |
* The post update registry. | |
* | |
* @var \Drupal\Core\Update\UpdateRegistry | |
*/ | |
protected $postUpdateRegistry; | |
/** | |
* Constructs a new UpdateController. | |
* | |
* @param string $root | |
* The app root. | |
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable_factory | |
* The keyvalue expirable factory. | |
* @param \Drupal\Core\Cache\CacheBackendInterface $cache | |
* A cache backend interface. | |
* @param \Drupal\Core\State\StateInterface $state | |
* The state service. | |
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
* The module handler. | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* The current user. | |
* @param \Drupal\Core\Render\BareHtmlPageRendererInterface $bare_html_page_renderer | |
* The bare HTML page renderer. | |
* @param \Drupal\Core\Update\UpdateRegistry $post_update_registry | |
* The post update registry. | |
*/ | |
public function __construct($root, KeyValueExpirableFactoryInterface $key_value_expirable_factory, CacheBackendInterface $cache, StateInterface $state, ModuleHandlerInterface $module_handler, AccountInterface $account, BareHtmlPageRendererInterface $bare_html_page_renderer, UpdateRegistry $post_update_registry) { | |
$this->root = $root; | |
$this->keyValueExpirableFactory = $key_value_expirable_factory; | |
$this->cache = $cache; | |
$this->state = $state; | |
$this->moduleHandler = $module_handler; | |
$this->account = $account; | |
$this->bareHtmlPageRenderer = $bare_html_page_renderer; | |
$this->postUpdateRegistry = $post_update_registry; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container) { | |
return new static( | |
$container->get('app.root'), | |
$container->get('keyvalue.expirable'), | |
$container->get('cache.default'), | |
$container->get('state'), | |
$container->get('module_handler'), | |
$container->get('current_user'), | |
$container->get('bare_html_page_renderer'), | |
$container->get('update.post_update_registry') | |
); | |
} | |
/** | |
* Returns a database update page. | |
* | |
* @param string $op | |
* The update operation to perform. Can be any of the below: | |
* - info | |
* - selection | |
* - run | |
* - results | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request object. | |
* | |
* @return \Symfony\Component\HttpFoundation\Response | |
* A response object object. | |
*/ | |
public function handle($op, Request $request) { | |
require_once $this->root . '/core/includes/install.inc'; | |
require_once $this->root . '/core/includes/update.inc'; | |
drupal_load_updates(); | |
update_fix_compatibility(); | |
if ($request->query->get('continue')) { | |
$_SESSION['update_ignore_warnings'] = TRUE; | |
} | |
$regions = array(); | |
$requirements = update_check_requirements(); | |
$severity = drupal_requirements_severity($requirements); | |
if ($severity == REQUIREMENT_ERROR || ($severity == REQUIREMENT_WARNING && empty($_SESSION['update_ignore_warnings']))) { | |
$regions['sidebar_first'] = $this->updateTasksList('requirements'); | |
$output = $this->requirements($severity, $requirements, $request); | |
} | |
else { | |
switch ($op) { | |
case 'selection': | |
$regions['sidebar_first'] = $this->updateTasksList('selection'); | |
$output = $this->selection($request); | |
break; | |
case 'run': | |
$regions['sidebar_first'] = $this->updateTasksList('run'); | |
$output = $this->triggerBatch($request); | |
break; | |
case 'info': | |
$regions['sidebar_first'] = $this->updateTasksList('info'); | |
$output = $this->info($request); | |
break; | |
case 'results': | |
$regions['sidebar_first'] = $this->updateTasksList('results'); | |
$output = $this->results($request); | |
break; | |
// Regular batch ops : defer to batch processing API. | |
default: | |
require_once $this->root . '/core/includes/batch.inc'; | |
$regions['sidebar_first'] = $this->updateTasksList('run'); | |
$output = _batch_page($request); | |
break; | |
} | |
} | |
if ($output instanceof Response) { | |
return $output; | |
} | |
$title = isset($output['#title']) ? $output['#title'] : $this->t('Drupal database update'); | |
return $this->bareHtmlPageRenderer->renderBarePage($output, $title, 'maintenance_page', $regions); | |
} | |
/** | |
* Returns the info database update page. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request. | |
* | |
* @return array | |
* A render array. | |
*/ | |
protected function info(Request $request) { | |
// Change query-strings on css/js files to enforce reload for all users. | |
_drupal_flush_css_js(); | |
// Flush the cache of all data for the update status module. | |
$this->keyValueExpirableFactory->get('update')->deleteAll(); | |
$this->keyValueExpirableFactory->get('update_available_release')->deleteAll(); | |
$build['info_header'] = array( | |
'#markup' => '<p>' . $this->t('Use this utility to update your database whenever a new release of Drupal or a module is installed.') . '</p><p>' . $this->t('For more detailed information, see the <a href="https://www.drupal.org/upgrade">upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.') . '</p>', | |
); | |
$info[] = $this->t("<strong>Back up your code</strong>. Hint: when backing up module code, do not leave that backup in the 'modules' or 'sites/*/modules' directories as this may confuse Drupal's auto-discovery mechanism."); | |
$info[] = $this->t('Put your site into <a href=":url">maintenance mode</a>.', array( | |
':url' => Url::fromRoute('system.site_maintenance_mode')->toString(TRUE)->getGeneratedUrl(), | |
)); | |
$info[] = $this->t('<strong>Back up your database</strong>. This process will change your database values and in case of emergency you may need to revert to a backup.'); | |
$info[] = $this->t('Install your new files in the appropriate location, as described in the handbook.'); | |
$build['info'] = array( | |
'#theme' => 'item_list', | |
'#list_type' => 'ol', | |
'#items' => $info, | |
); | |
$build['info_footer'] = array( | |
'#markup' => '<p>' . $this->t('When you have performed the steps above, you may proceed.') . '</p>', | |
); | |
$build['link'] = array( | |
'#type' => 'link', | |
'#title' => $this->t('Continue'), | |
'#attributes' => array('class' => array('button', 'button--primary')), | |
// @todo Revisit once https://www.drupal.org/node/2548095 is in. | |
'#url' => Url::fromUri('base://selection'), | |
); | |
return $build; | |
} | |
/** | |
* Renders a list of available database updates. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request. | |
* | |
* @return array | |
* A render array. | |
*/ | |
protected function selection(Request $request) { | |
// Make sure there is no stale theme registry. | |
$this->cache->deleteAll(); | |
$count = 0; | |
$incompatible_count = 0; | |
$build['start'] = array( | |
'#tree' => TRUE, | |
'#type' => 'details', | |
); | |
// Ensure system.module's updates appear first. | |
$build['start']['system'] = array(); | |
$starting_updates = array(); | |
$incompatible_updates_exist = FALSE; | |
$updates_per_module = []; | |
foreach (['update', 'post_update'] as $update_type) { | |
switch ($update_type) { | |
case 'update': | |
$updates = update_get_update_list(); | |
break; | |
case 'post_update': | |
$updates = $this->postUpdateRegistry->getPendingUpdateInformation(); | |
break; | |
} | |
foreach ($updates as $module => $update) { | |
if (!isset($update['start'])) { | |
$build['start'][$module] = array( | |
'#type' => 'item', | |
'#title' => $module . ' module', | |
'#markup' => $update['warning'], | |
'#prefix' => '<div class="messages messages--warning">', | |
'#suffix' => '</div>', | |
); | |
$incompatible_updates_exist = TRUE; | |
continue; | |
} | |
if (!empty($update['pending'])) { | |
$updates_per_module += [$module => []]; | |
$updates_per_module[$module] = array_merge($updates_per_module[$module], $update['pending']); | |
$build['start'][$module] = array( | |
'#type' => 'hidden', | |
'#value' => $update['start'], | |
); | |
// Store the previous items in order to merge normal updates and | |
// post_update functions together. | |
$build['start'][$module] = array( | |
'#theme' => 'item_list', | |
'#items' => $updates_per_module[$module], | |
'#title' => $module . ' module', | |
); | |
if ($update_type === 'update') { | |
$starting_updates[$module] = $update['start']; | |
} | |
} | |
if (isset($update['pending'])) { | |
$count = $count + count($update['pending']); | |
} | |
} | |
} | |
// Find and label any incompatible updates. | |
foreach (update_resolve_dependencies($starting_updates) as $data) { | |
if (!$data['allowed']) { | |
$incompatible_updates_exist = TRUE; | |
$incompatible_count++; | |
$module_update_key = $data['module'] . '_updates'; | |
if (isset($build['start'][$module_update_key]['#items'][$data['number']])) { | |
if ($data['missing_dependencies']) { | |
$text = $this->t('This update will been skipped due to the following missing dependencies:') . '<em>' . implode(', ', $data['missing_dependencies']) . '</em>'; | |
} | |
else { | |
$text = $this->t("This update will be skipped due to an error in the module's code."); | |
} | |
$build['start'][$module_update_key]['#items'][$data['number']] .= '<div class="warning">' . $text . '</div>'; | |
} | |
// Move the module containing this update to the top of the list. | |
$build['start'] = array($module_update_key => $build['start'][$module_update_key]) + $build['start']; | |
} | |
} | |
// Warn the user if any updates were incompatible. | |
if ($incompatible_updates_exist) { | |
drupal_set_message($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'), 'warning'); | |
} | |
if (empty($count)) { | |
drupal_set_message($this->t('No pending updates.')); | |
unset($build); | |
$build['links'] = array( | |
'#theme' => 'links', | |
'#links' => $this->helpfulLinks($request), | |
); | |
// No updates to run, so caches won't get flushed later. Clear them now. | |
drupal_flush_all_caches(); | |
} | |
else { | |
$build['help'] = array( | |
'#markup' => '<p>' . $this->t('The version of Drupal you are updating from has been automatically detected.') . '</p>', | |
'#weight' => -5, | |
); | |
if ($incompatible_count) { | |
$build['start']['#title'] = $this->formatPlural( | |
$count, | |
'1 pending update (@number_applied to be applied, @number_incompatible skipped)', | |
'@count pending updates (@number_applied to be applied, @number_incompatible skipped)', | |
array('@number_applied' => $count - $incompatible_count, '@number_incompatible' => $incompatible_count) | |
); | |
} | |
else { | |
$build['start']['#title'] = $this->formatPlural($count, '1 pending update', '@count pending updates'); | |
} | |
// @todo Simplify with https://www.drupal.org/node/2548095 | |
$base_url = str_replace('/update.php', '', $request->getBaseUrl()); | |
$url = (new Url('system.db_update', array('op' => 'run')))->setOption('base_url', $base_url); | |
$build['link'] = array( | |
'#type' => 'link', | |
'#title' => $this->t('Apply pending updates'), | |
'#attributes' => array('class' => array('button', 'button--primary')), | |
'#weight' => 5, | |
'#url' => $url, | |
); | |
} | |
return $build; | |
} | |
/** | |
* Displays results of the update script with any accompanying errors. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request. | |
* | |
* @return array | |
* A render array. | |
*/ | |
protected function results(Request $request) { | |
// @todo Simplify with https://www.drupal.org/node/2548095 | |
$base_url = str_replace('/update.php', '', $request->getBaseUrl()); | |
// Report end result. | |
$dblog_exists = $this->moduleHandler->moduleExists('dblog'); | |
if ($dblog_exists && $this->account->hasPermission('access site reports')) { | |
$log_message = $this->t('All errors have been <a href=":url">logged</a>.', array( | |
':url' => Url::fromRoute('dblog.overview')->setOption('base_url', $base_url)->toString(TRUE)->getGeneratedUrl(), | |
)); | |
} | |
else { | |
$log_message = $this->t('All errors have been logged.'); | |
} | |
if (!empty($_SESSION['update_success'])) { | |
$message = '<p>' . $this->t('Updates were attempted. If you see no failures below, you may proceed happily back to your <a href=":url">site</a>. Otherwise, you may need to update your database manually.', array(':url' => Url::fromRoute('<front>')->setOption('base_url', $base_url)->toString(TRUE)->getGeneratedUrl())) . ' ' . $log_message . '</p>'; | |
} | |
else { | |
$last = reset($_SESSION['updates_remaining']); | |
list($module, $version) = array_pop($last); | |
$message = '<p class="error">' . $this->t('The update process was aborted prematurely while running <strong>update #@version in @module.module</strong>.', array( | |
'@version' => $version, | |
'@module' => $module, | |
)) . ' ' . $log_message; | |
if ($dblog_exists) { | |
$message .= ' ' . $this->t('You may need to check the <code>watchdog</code> database table manually.'); | |
} | |
$message .= '</p>'; | |
} | |
if (Settings::get('update_free_access')) { | |
$message .= '<p>' . $this->t("<strong>Reminder: don't forget to set the <code>\$settings['update_free_access']</code> value in your <code>settings.php</code> file back to <code>FALSE</code>.</strong>") . '</p>'; | |
} | |
$build['message'] = array( | |
'#markup' => $message, | |
); | |
$build['links'] = array( | |
'#theme' => 'links', | |
'#links' => $this->helpfulLinks($request), | |
); | |
// Output a list of info messages. | |
if (!empty($_SESSION['update_results'])) { | |
$all_messages = array(); | |
foreach ($_SESSION['update_results'] as $module => $updates) { | |
if ($module != '#abort') { | |
$module_has_message = FALSE; | |
$info_messages = array(); | |
foreach ($updates as $name => $queries) { | |
$messages = array(); | |
foreach ($queries as $query) { | |
// If there is no message for this update, don't show anything. | |
if (empty($query['query'])) { | |
continue; | |
} | |
if ($query['success']) { | |
$messages[] = array( | |
'#wrapper_attributes' => array('class' => array('success')), | |
'#markup' => $query['query'], | |
); | |
} | |
else { | |
$messages[] = array( | |
'#wrapper_attributes' => array('class' => array('failure')), | |
'#markup' => '<strong>' . $this->t('Failed:') . '</strong> ' . $query['query'], | |
); | |
} | |
} | |
if ($messages) { | |
$module_has_message = TRUE; | |
if (is_numeric($name)) { | |
$title = $this->t('Update #@count', ['@count' => $name]); | |
} | |
else { | |
$title = $this->t('Update @name', ['@name' => trim($name, '_')]); | |
} | |
$info_messages[] = array( | |
'#theme' => 'item_list', | |
'#items' => $messages, | |
'#title' => $title, | |
); | |
} | |
} | |
// If there were any messages then prefix them with the module name | |
// and add it to the global message list. | |
if ($module_has_message) { | |
$all_messages[] = array( | |
'#type' => 'container', | |
'#prefix' => '<h3>' . $this->t('@module module', array('@module' => $module)) . '</h3>', | |
'#children' => $info_messages, | |
); | |
} | |
} | |
} | |
if ($all_messages) { | |
$build['query_messages'] = array( | |
'#type' => 'container', | |
'#children' => $all_messages, | |
'#attributes' => array('class' => array('update-results')), | |
'#prefix' => '<h2>' . $this->t('The following updates returned messages:') . '</h2>', | |
); | |
} | |
} | |
unset($_SESSION['update_results']); | |
unset($_SESSION['update_success']); | |
unset($_SESSION['update_ignore_warnings']); | |
return $build; | |
} | |
/** | |
* Renders a list of requirement errors or warnings. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request. | |
* | |
* @return array | |
* A render array. | |
*/ | |
public function requirements($severity, array $requirements, Request $request) { | |
$options = $severity == REQUIREMENT_WARNING ? array('continue' => 1) : array(); | |
// @todo Revisit once https://www.drupal.org/node/2548095 is in. Something | |
// like Url::fromRoute('system.db_update')->setOptions() should then be | |
// possible. | |
$try_again_url = Url::fromUri($request->getUriForPath(''))->setOptions(['query' => $options])->toString(TRUE)->getGeneratedUrl(); | |
$build['status_report'] = array( | |
'#theme' => 'status_report', | |
'#requirements' => $requirements, | |
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', array(':url' => $try_again_url)) | |
); | |
$build['#title'] = $this->t('Requirements problem'); | |
return $build; | |
} | |
/** | |
* Provides the update task list render array. | |
* | |
* @param string $active | |
* The active task. | |
* Can be one of 'requirements', 'info', 'selection', 'run', 'results'. | |
* | |
* @return array | |
* A render array. | |
*/ | |
protected function updateTasksList($active = NULL) { | |
// Default list of tasks. | |
$tasks = array( | |
'requirements' => $this->t('Verify requirements'), | |
'info' => $this->t('Overview'), | |
'selection' => $this->t('Review updates'), | |
'run' => $this->t('Run updates'), | |
'results' => $this->t('Review log'), | |
); | |
$task_list = array( | |
'#theme' => 'maintenance_task_list', | |
'#items' => $tasks, | |
'#active' => $active, | |
); | |
return $task_list; | |
} | |
/** | |
* Starts the database update batch process. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request object. | |
*/ | |
protected function triggerBatch(Request $request) { | |
$maintenance_mode = $this->state->get('system.maintenance_mode', FALSE); | |
// Store the current maintenance mode status in the session so that it can | |
// be restored at the end of the batch. | |
$_SESSION['maintenance_mode'] = $maintenance_mode; | |
// During the update, always put the site into maintenance mode so that | |
// in-progress schema changes do not affect visiting users. | |
if (empty($maintenance_mode)) { | |
$this->state->set('system.maintenance_mode', TRUE); | |
} | |
$operations = array(); | |
// Resolve any update dependencies to determine the actual updates that will | |
// be run and the order they will be run in. | |
$start = $this->getModuleUpdates(); | |
$updates = update_resolve_dependencies($start); | |
// Store the dependencies for each update function in an array which the | |
// batch API can pass in to the batch operation each time it is called. (We | |
// do not store the entire update dependency array here because it is | |
// potentially very large.) | |
$dependency_map = array(); | |
foreach ($updates as $function => $update) { | |
$dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : array(); | |
} | |
// Determine updates to be performed. | |
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']]); | |
} | |
$operations[] = array('update_do_one', array($update['module'], $update['number'], $dependency_map[$function])); | |
} | |
} | |
$post_updates = $this->postUpdateRegistry->getPendingUpdateFunctions(); | |
if ($post_updates) { | |
// Now we rebuild all caches and after that execute the hook_post_update() | |
// functions. | |
$operations[] = ['drupal_flush_all_caches', []]; | |
foreach ($post_updates as $function) { | |
$operations[] = ['update_invoke_post_update', [$function]]; | |
} | |
} | |
$batch['operations'] = $operations; | |
$batch += array( | |
'title' => $this->t('Updating'), | |
'init_message' => $this->t('Starting updates'), | |
'error_message' => $this->t('An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.'), | |
'finished' => array('\Drupal\system\Controller\DbUpdateController', 'batchFinished'), | |
); | |
batch_set($batch); | |
// @todo Revisit once https://www.drupal.org/node/2548095 is in. | |
return batch_process(Url::fromUri('base://results'), Url::fromUri('base://start')); | |
} | |
/** | |
* Finishes the update process and stores the results for eventual display. | |
* | |
* After the updates run, all caches are flushed. The update results are | |
* stored into the session (for example, to be displayed on the update results | |
* page in update.php). Additionally, if the site was off-line, now that the | |
* update process is completed, the site is set back online. | |
* | |
* @param $success | |
* Indicate that the batch API tasks were all completed successfully. | |
* @param array $results | |
* An array of all the results that were updated in update_do_one(). | |
* @param array $operations | |
* A list of all the operations that had not been completed by the batch API. | |
*/ | |
public static function batchFinished($success, $results, $operations) { | |
// No updates to run, so caches won't get flushed later. Clear them now. | |
drupal_flush_all_caches(); | |
$_SESSION['update_results'] = $results; | |
$_SESSION['update_success'] = $success; | |
$_SESSION['updates_remaining'] = $operations; | |
// Now that the update is done, we can put the site back online if it was | |
// previously not in maintenance mode. | |
if (empty($_SESSION['maintenance_mode'])) { | |
\Drupal::state()->set('system.maintenance_mode', FALSE); | |
} | |
unset($_SESSION['maintenance_mode']); | |
} | |
/** | |
* Provides links to the homepage and administration pages. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The current request. | |
* | |
* @return array | |
* An array of links. | |
*/ | |
protected function helpfulLinks(Request $request) { | |
// @todo Simplify with https://www.drupal.org/node/2548095 | |
$base_url = str_replace('/update.php', '', $request->getBaseUrl()); | |
$links['front'] = array( | |
'title' => $this->t('Front page'), | |
'url' => Url::fromRoute('<front>')->setOption('base_url', $base_url), | |
); | |
if ($this->account->hasPermission('access administration pages')) { | |
$links['admin-pages'] = array( | |
'title' => $this->t('Administration pages'), | |
'url' => Url::fromRoute('system.admin')->setOption('base_url', $base_url), | |
); | |
} | |
return $links; | |
} | |
/** | |
* Retrieves module updates. | |
* | |
* @return array | |
* The module updates that can be performed. | |
*/ | |
protected function getModuleUpdates() { | |
$return = array(); | |
$updates = update_get_update_list(); | |
foreach ($updates as $module => $update) { | |
$return[$module] = $update['start']; | |
} | |
return $return; | |
} | |
} |