class ProjectCoreCompatibility

Same name in other branches
  1. 9 core/modules/update/src/ProjectCoreCompatibility.php \Drupal\update\ProjectCoreCompatibility
  2. 8.9.x core/modules/update/src/ProjectCoreCompatibility.php \Drupal\update\ProjectCoreCompatibility
  3. 10 core/modules/update/src/ProjectCoreCompatibility.php \Drupal\update\ProjectCoreCompatibility

Utility class to set core compatibility messages for project releases.

@internal This class implements logic used by update_calculate_project_status(). It should not be called directly.

Hierarchy

Expanded class hierarchy of ProjectCoreCompatibility

2 files declare their use of ProjectCoreCompatibility
ProjectCoreCompatibilityTest.php in core/modules/update/tests/src/Unit/ProjectCoreCompatibilityTest.php
update.compare.inc in core/modules/update/update.compare.inc

File

core/modules/update/src/ProjectCoreCompatibility.php, line 16

Namespace

Drupal\update
View source
final class ProjectCoreCompatibility {
    use StringTranslationTrait;
    
    /**
     * The currently installed version of Drupal core.
     *
     * @var string
     */
    protected $existingCoreVersion;
    
    /**
     * Cache of core versions that are available for updates.
     *
     * @var string[]
     */
    protected $possibleCoreUpdateVersions;
    
    /**
     * Cache of core compatibility messages per core version constraint.
     *
     * Keys are core version constraint strings, values are human-readable
     * messages about the versions of core that version constraint maps to.
     *
     * This list is cached since many project releases will use the same core
     * compatibility constraint.
     *
     * @var string[]
     */
    protected $compatibilityMessages = [];
    
    /**
     * Constructs a ProjectCoreCompatibility object.
     *
     * @param array $core_data
     *   The project data for Drupal core as returned by
     *   \Drupal\update\UpdateManagerInterface::getProjects() and then processed
     *   by update_process_project_info() and
     *   update_calculate_project_update_status().
     * @param array $core_releases
     *   The Drupal core available releases.
     * @param array $supported_branches
     *   An array for supported branches as returned by drupal.org update XML.
     *
     * @see \Drupal\update\UpdateManagerInterface::getProjects()
     * @see update_process_project_info()
     * @see update_calculate_project_update_status()
     */
    public function __construct(array $core_data, array $core_releases, array $supported_branches) {
        if (isset($core_data['existing_version'])) {
            $this->existingCoreVersion = $core_data['existing_version'];
            $this->possibleCoreUpdateVersions = $this->getPossibleCoreUpdateVersions($core_releases, $supported_branches);
        }
    }
    
    /**
     * Gets the core versions that should be considered for compatibility ranges.
     *
     * @param array $core_releases
     *   The Drupal core available releases.
     * @param array $supported_branches
     *   An array for supported branches as returned by drupal.org update XML.
     *
     * @return string[]
     *   The core version numbers that are possible to update the site to.
     */
    protected function getPossibleCoreUpdateVersions(array $core_releases, array $supported_branches) {
        if (!isset($core_releases[$this->existingCoreVersion])) {
            // If we can't determine the existing version of core then we can't
            // calculate the core compatibility of a given release based on core
            // versions after the existing version.
            return [];
        }
        $supported_versions = array_filter(array_keys($core_releases), function ($version) use ($supported_branches) {
            foreach ($supported_branches as $supported_branch) {
                if (strpos($version, $supported_branch) === 0) {
                    return TRUE;
                }
            }
            return FALSE;
        });
        $possible_core_update_versions = Semver::satisfiedBy($supported_versions, '>= ' . $this->existingCoreVersion);
        $possible_core_update_versions = Semver::sort($possible_core_update_versions);
        $possible_core_update_versions = array_filter($possible_core_update_versions, function ($version) {
            return VersionParser::parseStability($version) === 'stable';
        });
        return $possible_core_update_versions;
    }
    
    /**
     * Sets core compatibility messages for project releases.
     *
     * @param array &$project_data
     *   The project data as returned by
     *   \Drupal\update\UpdateManagerInterface::getProjects() and then processed
     *   by update_process_project_info() and
     *   update_calculate_project_update_status(). If set, the following keys are
     *   used in this method:
     *   - recommended (string): A project version number.
     *   - latest_version (string): A project version number.
     *   - also (string[]): Project version numbers.
     *   - releases (array[]): An array where the keys are project version numbers
     *     and the values are arrays of project release information.
     *   - security updates (array[]): An array of project release information.
     *
     * @see \Drupal\update\UpdateManagerInterface::getProjects()
     * @see update_process_project_info()
     * @see update_calculate_project_update_status()
     */
    public function setReleaseMessage(array &$project_data) {
        if (empty($this->possibleCoreUpdateVersions)) {
            return;
        }
        // Get the various releases that will need to have core compatibility
        // messages added to them.
        $releases_to_set = [];
        $versions = [];
        if (!empty($project_data['recommended'])) {
            $versions[] = $project_data['recommended'];
        }
        if (!empty($project_data['latest_version'])) {
            $versions[] = $project_data['latest_version'];
        }
        if (!empty($project_data['also'])) {
            $versions = array_merge($versions, $project_data['also']);
        }
        foreach ($versions as $version) {
            if (isset($project_data['releases'][$version])) {
                $releases_to_set[] =& $project_data['releases'][$version];
            }
        }
        if (!empty($project_data['security updates'])) {
            foreach ($project_data['security updates'] as &$security_update) {
                $releases_to_set[] =& $security_update;
            }
        }
        foreach ($releases_to_set as &$release) {
            if (!empty($release['core_compatibility'])) {
                $release['core_compatible'] = $this->isCoreCompatible($release['core_compatibility']);
                $release['core_compatibility_message'] = $this->createMessageFromCoreCompatibility($release['core_compatibility']);
            }
        }
    }
    
    /**
     * Determines if a release is compatible with the currently installed core.
     *
     * @param string $core_compatibility_constraint
     *   A semantic version constraint.
     *
     * @return bool
     *   TRUE if the given constraint is satisfied by the currently installed
     *   version of Drupal core, otherwise FALSE.
     */
    protected function isCoreCompatible($core_compatibility_constraint) {
        try {
            return Semver::satisfies($this->existingCoreVersion, $core_compatibility_constraint);
        } catch (\Exception) {
            return FALSE;
        }
    }
    
    /**
     * Creates core a compatibility message from a semantic version constraint.
     *
     * @param string $core_compatibility_constraint
     *   A semantic version constraint.
     *
     * @return string
     *   The core compatibility message.
     */
    protected function createMessageFromCoreCompatibility($core_compatibility_constraint) {
        if (!isset($this->compatibilityMessages[$core_compatibility_constraint])) {
            $core_compatibility_ranges = $this->getCompatibilityRanges($core_compatibility_constraint);
            $range_messages = [];
            foreach ($core_compatibility_ranges as $core_compatibility_range) {
                if (count($core_compatibility_range) === 2) {
                    $range_messages[] = $this->t('@low_version_number to @high_version_number', [
                        '@low_version_number' => $core_compatibility_range[0],
                        '@high_version_number' => $core_compatibility_range[1],
                    ]);
                }
                else {
                    $range_messages[] = $core_compatibility_range[0];
                }
            }
            $this->compatibilityMessages[$core_compatibility_constraint] = $this->t('Requires Drupal core:') . ' ' . implode(', ', $range_messages);
        }
        return $this->compatibilityMessages[$core_compatibility_constraint];
    }
    
    /**
     * Gets the compatibility ranges for a semantic version constraint.
     *
     * @param string $core_compatibility_constraint
     *   A semantic version constraint.
     *
     * @return array[]
     *   An array compatibility ranges. If a range array has 2 elements then this
     *   denotes a range of compatibility between and including the 2 versions. If
     *   the range has 1 element then it denotes compatibility with a single
     *   version.
     */
    protected function getCompatibilityRanges($core_compatibility_constraint) {
        $compatibility_ranges = [];
        foreach ($this->possibleCoreUpdateVersions as $possible_core_update_version) {
            if (Semver::satisfies($possible_core_update_version, $core_compatibility_constraint)) {
                if (empty($range)) {
                    $range[] = $possible_core_update_version;
                }
                else {
                    $range[1] = $possible_core_update_version;
                }
            }
            else {
                // If core version does not satisfy the constraint and there is a non
                // empty range, add it to the list of ranges.
                if (!empty($range)) {
                    $compatibility_ranges[] = $range;
                    // Start a new range.
                    $range = [];
                }
            }
        }
        if (!empty($range)) {
            $compatibility_ranges[] = $range;
        }
        return $compatibility_ranges;
    }

}

Members

Title Sort descending Modifiers Object type Summary Overrides
ProjectCoreCompatibility::$compatibilityMessages protected property Cache of core compatibility messages per core version constraint.
ProjectCoreCompatibility::$existingCoreVersion protected property The currently installed version of Drupal core.
ProjectCoreCompatibility::$possibleCoreUpdateVersions protected property Cache of core versions that are available for updates.
ProjectCoreCompatibility::createMessageFromCoreCompatibility protected function Creates core a compatibility message from a semantic version constraint.
ProjectCoreCompatibility::getCompatibilityRanges protected function Gets the compatibility ranges for a semantic version constraint.
ProjectCoreCompatibility::getPossibleCoreUpdateVersions protected function Gets the core versions that should be considered for compatibility ranges.
ProjectCoreCompatibility::isCoreCompatible protected function Determines if a release is compatible with the currently installed core.
ProjectCoreCompatibility::setReleaseMessage public function Sets core compatibility messages for project releases.
ProjectCoreCompatibility::__construct public function Constructs a ProjectCoreCompatibility object.
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.

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