View source
<?php
namespace Drupal\update;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
final class ProjectSecurityRequirement {
use StringTranslationTrait;
protected $projectTitle;
private $securityCoverageInfo;
private $nextMajorMinorVersion;
private $existingMajorMinorVersion;
private function __construct($project_title = NULL, array $security_coverage_info = [], $existing_major_minor_version = NULL, $next_major_minor_version = NULL) {
$this->projectTitle = $project_title;
$this->securityCoverageInfo = $security_coverage_info;
$this->existingMajorMinorVersion = $existing_major_minor_version;
$this->nextMajorMinorVersion = $next_major_minor_version;
}
public static function createFromProjectDataAndSecurityCoverageInfo(array $project_data, array $security_coverage_info) {
if ($project_data['project_type'] !== 'core' || $project_data['name'] !== 'drupal' || empty($security_coverage_info)) {
return new static();
}
if (isset($project_data['existing_version'])) {
list($major, $minor) = explode('.', $project_data['existing_version']);
$existing_version = "{$major}.{$minor}";
$next_version = "{$major}." . ((int) $minor + 1);
return new static($project_data['title'], $security_coverage_info, $existing_version, $next_version);
}
return new static($project_data['title'], $security_coverage_info);
}
public function getRequirement() {
if (isset($this->securityCoverageInfo['security_coverage_end_version'])) {
$requirement = $this
->getVersionEndRequirement();
}
elseif (isset($this->securityCoverageInfo['security_coverage_end_date'])) {
$requirement = $this
->getDateEndRequirement();
}
else {
return [];
}
$requirement['title'] = $this
->t('Drupal core security coverage');
return $requirement;
}
private function getVersionEndRequirement() {
$requirement = [];
if ($security_coverage_message = $this
->getVersionEndCoverageMessage()) {
$requirement['description'] = $security_coverage_message;
if ($this->securityCoverageInfo['additional_minors_coverage'] > 0) {
$requirement['value'] = $this
->t('Covered until @end_version', [
'@end_version' => $this->securityCoverageInfo['security_coverage_end_version'],
]);
$requirement['severity'] = $this->securityCoverageInfo['additional_minors_coverage'] > 1 ? REQUIREMENT_INFO : REQUIREMENT_WARNING;
}
else {
$requirement['value'] = $this
->t('Coverage has ended');
$requirement['severity'] = REQUIREMENT_ERROR;
}
}
return $requirement;
}
private function getVersionEndCoverageMessage() {
if ($this->securityCoverageInfo['additional_minors_coverage'] > 0) {
if ($this->securityCoverageInfo['additional_minors_coverage'] === 1) {
$message['coverage_message'] = [
'#markup' => $this
->t('<a href=":update_status_report">Update to @next_minor or higher</a> soon to continue receiving security updates.', [
':update_status_report' => Url::fromRoute('update.status')
->toString(),
'@next_minor' => $this->nextMajorMinorVersion,
]),
'#suffix' => ' ',
];
}
}
else {
$message['coverage_message'] = [
'#markup' => $this
->getVersionNoSecurityCoverageMessage(),
'#suffix' => ' ',
];
}
$message['release_cycle_link'] = [
'#markup' => $this
->getReleaseCycleLink(),
];
return $message;
}
private function getDateEndRequirement() {
$requirement = [];
$time = \Drupal::service('datetime.time');
$date_formatter = \Drupal::service('date.formatter');
if (substr_count($this->securityCoverageInfo['security_coverage_end_date'], '-') === 2) {
$date_format = 'Y-m-d';
$full_security_coverage_end_date = $this->securityCoverageInfo['security_coverage_end_date'];
}
else {
$date_format = 'Y-m';
$full_security_coverage_end_date = $this->securityCoverageInfo['security_coverage_end_date'] . '-15';
}
$comparable_request_date = $date_formatter
->format($time
->getRequestTime(), 'custom', $date_format);
if ($this->securityCoverageInfo['security_coverage_end_date'] <= $comparable_request_date) {
$requirement['value'] = $this
->t('Coverage has ended');
$requirement['severity'] = REQUIREMENT_ERROR;
$requirement['description']['coverage_message'] = [
'#markup' => $this
->getVersionNoSecurityCoverageMessage(),
'#suffix' => ' ',
];
}
else {
$security_coverage_end_timestamp = \DateTime::createFromFormat('Y-m-d', $full_security_coverage_end_date)
->getTimestamp();
$output_date_format = $date_format === 'Y-m-d' ? 'Y-M-d' : 'Y-M';
$formatted_end_date = $date_formatter
->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;
$request_date = $date_formatter
->format($time
->getRequestTime(), 'custom', 'Y-m-d');
if (!empty($this->securityCoverageInfo['security_coverage_ending_warn_date']) && $this->securityCoverageInfo['security_coverage_ending_warn_date'] <= $request_date) {
$requirement['description']['coverage_message'] = [
'#markup' => $this
->t('Update to a supported minor version soon to continue receiving security updates.'),
'#suffix' => ' ',
];
$requirement['severity'] = REQUIREMENT_WARNING;
}
}
$requirement['description']['release_cycle_link'] = [
'#markup' => $this
->getReleaseCycleLink(),
];
return $requirement;
}
private function getVersionNoSecurityCoverageMessage() {
return $this
->t('<a href=":update_status_report">Update to a supported minor</a> as soon as possible to continue receiving security updates.', [
':update_status_report' => Url::fromRoute('update.status')
->toString(),
]);
}
private function getReleaseCycleLink() {
return $this
->t('Visit the <a href=":url">release cycle overview</a> for more information on supported releases.', [
':url' => 'https://www.drupal.org/core/release-cycle-overview',
]);
}
}