class UpdateRequirements

Requirements for the update module.

Hierarchy

Expanded class hierarchy of UpdateRequirements

File

core/modules/update/src/Hook/UpdateRequirements.php, line 21

Namespace

Drupal\update\Hook
View source
class UpdateRequirements {
  use StringTranslationTrait;
  public function __construct(protected readonly ModuleHandlerInterface $moduleHandler) {
  }
  
  /**
   * Implements hook_runtime_requirements().
   *
   * Describes the status of the site regarding available updates. If
   * there is no update data, only one record will be returned, indicating that
   * the status of core can't be determined. If data is available, there will
   * be two records: one for core, and another for all of contrib (assuming
   * there are any contributed modules or themes installed on the site). In
   * addition to the fields expected by hook_requirements ('value', 'severity',
   * and optionally 'description'), this array will contain a 'reason'
   * attribute, which is an integer constant to indicate why the given status
   * is being returned (UPDATE_NOT_SECURE, UPDATE_NOT_CURRENT, or
   * UPDATE_UNKNOWN). This is used for generating the appropriate email
   * notification messages during update_cron(), and might be useful for other
   * modules that invoke update_runtime_requirements() to find out if the site
   * is up to date or not.
   *
   * @see _update_message_text()
   * @see _update_cron_notify()
   * @see \Drupal\update\UpdateManagerInterface
   */
  public function runtime() : array {
    $requirements = [];
    if ($available = update_get_available(FALSE)) {
      $this->moduleHandler
        ->loadInclude('update', 'inc', 'update.compare');
      $data = update_calculate_project_data($available);
      // First, populate the requirements for core:
      $requirements['update_core'] = $this->requirementCheck($data['drupal'], 'core');
      if (!empty($available['drupal']['releases'])) {
        $security_data = ProjectSecurityData::createFromProjectDataAndReleases($data['drupal'], $available['drupal']['releases'])->getCoverageInfo();
        if ($core_coverage_requirement = ProjectSecurityRequirement::createFromProjectDataAndSecurityCoverageInfo($data['drupal'], $security_data)->getRequirement()) {
          $requirements['coverage_core'] = $core_coverage_requirement;
        }
      }
      // We don't want to check drupal a second time.
      unset($data['drupal']);
      if (!empty($data)) {
        // Now, sort our $data array based on each project's status. The
        // status constants are numbered in the right order of precedence, so
        // we just need to make sure the projects are sorted in ascending
        // order of status, and we can look at the first project we find.
        uasort($data, '_update_project_status_sort');
        $first_project = reset($data);
        $requirements['update_contrib'] = $this->requirementCheck($first_project, 'contrib');
      }
    }
    else {
      $requirements['update_core']['title'] = $this->t('Drupal core update status');
      $requirements['update_core']['value'] = $this->t('No update data available');
      $requirements['update_core']['severity'] = RequirementSeverity::Warning;
      $requirements['update_core']['reason'] = UpdateFetcherInterface::UNKNOWN;
      $requirements['update_core']['description'] = _update_no_data();
    }
    return $requirements;
  }
  
  /**
   * Fills in the requirements array.
   *
   * This is shared for both core and contrib to generate the right elements in
   * the array for hook_runtime_requirements().
   *
   * @param array $project
   *   Array of information about the project we're testing as returned by
   *   update_calculate_project_data().
   * @param string $type
   *   What kind of project this is ('core' or 'contrib').
   *
   * @return array
   *   An array to be included in the nested $requirements array.
   *
   * @see hook_requirements()
   * @see update_requirements()
   * @see update_calculate_project_data()
   */
  protected function requirementCheck($project, $type) : array {
    $requirement = [];
    if ($type == 'core') {
      $requirement['title'] = $this->t('Drupal core update status');
    }
    else {
      $requirement['title'] = $this->t('Module and theme update status');
    }
    $status = $project['status'];
    if ($status != UpdateManagerInterface::CURRENT) {
      $requirement['reason'] = $status;
      $requirement['severity'] = RequirementSeverity::Error;
      // When updates are available, append the available updates link to the
      // message from _update_message_text(), and format the two translated
      // strings together in a single paragraph.
      $requirement['description'][] = [
        '#markup' => _update_message_text($type, $status),
      ];
      if (!in_array($status, [
        UpdateFetcherInterface::UNKNOWN,
        UpdateFetcherInterface::NOT_CHECKED,
        UpdateFetcherInterface::NOT_FETCHED,
        UpdateFetcherInterface::FETCH_PENDING,
      ])) {
        $requirement['description'][] = [
          '#prefix' => ' ',
          '#markup' => $this->t('See the <a href=":available_updates">available updates</a> page for more information.', [
            ':available_updates' => Url::fromRoute('update.status')->toString(),
          ]),
        ];
      }
    }
    switch ($status) {
      case UpdateManagerInterface::NOT_SECURE:
        $requirement_label = $this->t('Not secure!');
        break;

      case UpdateManagerInterface::REVOKED:
        $requirement_label = $this->t('Revoked!');
        break;

      case UpdateManagerInterface::NOT_SUPPORTED:
        $requirement_label = $this->t('Unsupported release');
        break;

      case UpdateManagerInterface::NOT_CURRENT:
        $requirement_label = $this->t('Out of date');
        $requirement['severity'] = RequirementSeverity::Warning;
        break;

      case UpdateFetcherInterface::UNKNOWN:
      case UpdateFetcherInterface::NOT_CHECKED:
      case UpdateFetcherInterface::NOT_FETCHED:
      case UpdateFetcherInterface::FETCH_PENDING:
        $requirement_label = $project['reason'] ?? $this->t('Can not determine status');
        $requirement['severity'] = RequirementSeverity::Warning;
        break;

      default:
        $requirement_label = $this->t('Up to date');
    }
    if ($status != UpdateManagerInterface::CURRENT && $type == 'core' && isset($project['recommended'])) {
      $requirement_label .= ' ' . $this->t('(version @version available)', [
        '@version' => $project['recommended'],
      ]);
    }
    $requirement['value'] = Link::fromTextAndUrl($requirement_label, Url::fromRoute('update.status'))->toString();
    return $requirement;
  }

}

Members

Title Sort descending Modifiers Object type Summary Overrides
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language. 1
UpdateRequirements::requirementCheck protected function Fills in the requirements array.
UpdateRequirements::runtime public function Implements hook_runtime_requirements().
UpdateRequirements::__construct public function

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.