You are here

protected function DbUpdateController::selection in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/system/src/Controller/DbUpdateController.php \Drupal\system\Controller\DbUpdateController::selection()

Renders a list of available database updates.

Parameters

\Symfony\Component\HttpFoundation\Request $request: The current request.

Return value

array A render array.

1 call to DbUpdateController::selection()
DbUpdateController::handle in core/modules/system/src/Controller/DbUpdateController.php
Returns a database update page.

File

core/modules/system/src/Controller/DbUpdateController.php, line 255

Class

DbUpdateController
Controller routines for database update routes.

Namespace

Drupal\system\Controller

Code

protected function selection(Request $request) {

  // Make sure there is no stale theme registry.
  $this->cache
    ->deleteAll();
  $count = 0;
  $incompatible_count = 0;
  $build['start'] = [
    '#tree' => TRUE,
    '#type' => 'details',
  ];

  // Ensure system.module's updates appear first.
  $build['start']['system'] = [];
  $starting_updates = [];
  $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] = [
          '#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] = [
          '#type' => 'hidden',
          '#value' => $update['start'],
        ];

        // Store the previous items in order to merge normal updates and
        // post_update functions together.
        $build['start'][$module] = [
          '#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'] = [
        $module_update_key => $build['start'][$module_update_key],
      ] + $build['start'];
    }
  }

  // Warn the user if any updates were incompatible.
  if ($incompatible_updates_exist) {
    $this
      ->messenger()
      ->addWarning($this
      ->t('Some of the pending updates cannot be applied because their dependencies were not met.'));
  }
  if (empty($count)) {
    $this
      ->messenger()
      ->addStatus($this
      ->t('No pending updates.'));
    unset($build);
    $build['links'] = [
      '#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'] = [
      '#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)', [
        '@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', [
      'op' => 'run',
    ]))
      ->setOption('base_url', $base_url);
    $build['link'] = [
      '#type' => 'link',
      '#title' => $this
        ->t('Apply pending updates'),
      '#attributes' => [
        'class' => [
          'button',
          'button--primary',
        ],
      ],
      '#weight' => 5,
      '#url' => $url,
      '#access' => $url
        ->access($this
        ->currentUser()),
    ];
  }
  return $build;
}