diff options
Diffstat (limited to 'core/modules/update/src')
-rw-r--r-- | core/modules/update/src/Hook/UpdateHooks.php | 10 | ||||
-rw-r--r-- | core/modules/update/src/Hook/UpdateRequirements.php | 162 | ||||
-rw-r--r-- | core/modules/update/src/ProjectSecurityRequirement.php | 11 | ||||
-rw-r--r-- | core/modules/update/src/UpdateRoot.php | 10 |
4 files changed, 180 insertions, 13 deletions
diff --git a/core/modules/update/src/Hook/UpdateHooks.php b/core/modules/update/src/Hook/UpdateHooks.php index 293882f01246..6577f7f1fc28 100644 --- a/core/modules/update/src/Hook/UpdateHooks.php +++ b/core/modules/update/src/Hook/UpdateHooks.php @@ -2,6 +2,7 @@ namespace Drupal\update\Hook; +use Drupal\Core\Extension\Requirement\RequirementSeverity; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\update\UpdateManagerInterface; use Drupal\Core\Url; @@ -77,8 +78,7 @@ class UpdateHooks { $verbose = TRUE; break; } - \Drupal::moduleHandler()->loadInclude('update', 'install'); - $status = update_requirements('runtime'); + $status = \Drupal::moduleHandler()->invoke('update', 'runtime_requirements'); foreach (['core', 'contrib'] as $report_type) { $type = 'update_' . $report_type; // hook_requirements() supports render arrays therefore we need to @@ -89,10 +89,10 @@ class UpdateHooks { } if (!empty($verbose)) { if (isset($status[$type]['severity'])) { - if ($status[$type]['severity'] == REQUIREMENT_ERROR) { + if ($status[$type]['severity'] === RequirementSeverity::Error) { \Drupal::messenger()->addError($status[$type]['description']); } - elseif ($status[$type]['severity'] == REQUIREMENT_WARNING) { + elseif ($status[$type]['severity'] === RequirementSeverity::Warning) { \Drupal::messenger()->addWarning($status[$type]['description']); } } @@ -178,8 +178,6 @@ class UpdateHooks { \Drupal::moduleHandler()->loadInclude('update', 'inc', 'update.fetch'); _update_cron_notify(); } - // Clear garbage from disk. - update_clear_update_disk_cache(); } /** diff --git a/core/modules/update/src/Hook/UpdateRequirements.php b/core/modules/update/src/Hook/UpdateRequirements.php new file mode 100644 index 000000000000..2f51f205b1a0 --- /dev/null +++ b/core/modules/update/src/Hook/UpdateRequirements.php @@ -0,0 +1,162 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\update\Hook; + +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Extension\Requirement\RequirementSeverity; +use Drupal\Core\Hook\Attribute\Hook; +use Drupal\Core\Link; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\Url; +use Drupal\update\ProjectSecurityData; +use Drupal\update\ProjectSecurityRequirement; +use Drupal\update\UpdateFetcherInterface; +use Drupal\update\UpdateManagerInterface; + +/** + * Requirements for the update module. + */ +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 + */ + #[Hook('runtime_requirements')] + 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; + } + +} diff --git a/core/modules/update/src/ProjectSecurityRequirement.php b/core/modules/update/src/ProjectSecurityRequirement.php index cc6fed789fea..331c65537c85 100644 --- a/core/modules/update/src/ProjectSecurityRequirement.php +++ b/core/modules/update/src/ProjectSecurityRequirement.php @@ -2,6 +2,7 @@ namespace Drupal\update; +use Drupal\Core\Extension\Requirement\RequirementSeverity; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Url; @@ -141,11 +142,11 @@ final class ProjectSecurityRequirement { 'Covered until @end_version', ['@end_version' => $this->securityCoverageInfo['security_coverage_end_version']] ); - $requirement['severity'] = $this->securityCoverageInfo['additional_minors_coverage'] > 1 ? REQUIREMENT_INFO : REQUIREMENT_WARNING; + $requirement['severity'] = $this->securityCoverageInfo['additional_minors_coverage'] > 1 ? RequirementSeverity::Info : RequirementSeverity::Warning; } else { $requirement['value'] = $this->t('Coverage has ended'); - $requirement['severity'] = REQUIREMENT_ERROR; + $requirement['severity'] = RequirementSeverity::Error; } } return $requirement; @@ -224,7 +225,7 @@ final class ProjectSecurityRequirement { if ($this->securityCoverageInfo['security_coverage_end_date'] <= $comparable_request_date) { // Security coverage is over. $requirement['value'] = $this->t('Coverage has ended'); - $requirement['severity'] = REQUIREMENT_ERROR; + $requirement['severity'] = RequirementSeverity::Error; $requirement['description']['coverage_message'] = [ '#markup' => $this->getVersionNoSecurityCoverageMessage(), '#suffix' => ' ', @@ -237,7 +238,7 @@ final class ProjectSecurityRequirement { ->format($security_coverage_end_timestamp, 'custom', $output_date_format); $translation_arguments = ['@date' => $formatted_end_date]; $requirement['value'] = $this->t('Covered until @date', $translation_arguments); - $requirement['severity'] = REQUIREMENT_INFO; + $requirement['severity'] = RequirementSeverity::Info; // 'security_coverage_ending_warn_date' will always be in the format // 'Y-m-d'. $request_date = $date_formatter->format($time->getRequestTime(), 'custom', 'Y-m-d'); @@ -246,7 +247,7 @@ final class ProjectSecurityRequirement { '#markup' => $this->t('Update to a supported version soon to continue receiving security updates.'), '#suffix' => ' ', ]; - $requirement['severity'] = REQUIREMENT_WARNING; + $requirement['severity'] = RequirementSeverity::Warning; } } $requirement['description']['release_cycle_link'] = ['#markup' => $this->getReleaseCycleLink()]; diff --git a/core/modules/update/src/UpdateRoot.php b/core/modules/update/src/UpdateRoot.php index a2f1619d6ea6..604e9ff0f529 100644 --- a/core/modules/update/src/UpdateRoot.php +++ b/core/modules/update/src/UpdateRoot.php @@ -6,7 +6,12 @@ use Drupal\Core\DrupalKernelInterface; use Symfony\Component\HttpFoundation\RequestStack; /** - * Gets the root path used by the Update Manager to install or update projects. + * Gets the root path used by the legacy Update Manager. + * + * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no + * replacement. Use composer to manage the code for your site. + * + * @see https://www.drupal.org/node/3522119 */ class UpdateRoot { @@ -32,7 +37,7 @@ class UpdateRoot { protected $updateRoot; /** - * Constructs an UpdateRootFactory instance. + * Constructs an UpdateRoot instance. * * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel * The Drupal kernel. @@ -40,6 +45,7 @@ class UpdateRoot { * The request stack. */ public function __construct(DrupalKernelInterface $drupal_kernel, RequestStack $request_stack) { + @trigger_error(__CLASS__ . ' is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no replacement. Use composer to manage the code for your site. See https://www.drupal.org/node/3522119', E_USER_DEPRECATED); $this->drupalKernel = $drupal_kernel; $this->requestStack = $request_stack; } |