class InfoParserDynamic
Same name in other branches
- 8.9.x core/lib/Drupal/Core/Extension/InfoParserDynamic.php \Drupal\Core\Extension\InfoParserDynamic
- 10 core/lib/Drupal/Core/Extension/InfoParserDynamic.php \Drupal\Core\Extension\InfoParserDynamic
- 11.x core/lib/Drupal/Core/Extension/InfoParserDynamic.php \Drupal\Core\Extension\InfoParserDynamic
Parses dynamic .info.yml files that might change during the page request.
Hierarchy
- class \Drupal\Core\Extension\InfoParserDynamic implements \Drupal\Core\Extension\InfoParserInterface
Expanded class hierarchy of InfoParserDynamic
2 files declare their use of InfoParserDynamic
- InstallCommand.php in core/
lib/ Drupal/ Core/ Command/ InstallCommand.php - UpdateUploadTest.php in core/
modules/ update/ tests/ src/ Functional/ UpdateUploadTest.php
File
-
core/
lib/ Drupal/ Core/ Extension/ InfoParserDynamic.php, line 12
Namespace
Drupal\Core\ExtensionView source
class InfoParserDynamic implements InfoParserInterface {
/**
* The root directory of the Drupal installation.
*
* @var string
*/
protected $root;
/**
* The earliest Drupal version that supports the 'core_version_requirement'.
*/
const FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION = '8.7.7';
/**
* InfoParserDynamic constructor.
*
* @param string|null $app_root
* The root directory of the Drupal installation.
*/
public function __construct(string $app_root = NULL) {
if ($app_root === NULL) {
// @todo https://www.drupal.org/project/drupal/issues/3087975 Require
// $app_root argument.
$app_root = \Drupal::hasService('kernel') ? \Drupal::root() : DRUPAL_ROOT;
}
$this->root = $app_root;
}
/**
* {@inheritdoc}
*/
public function parse($filename) {
if (!file_exists($filename)) {
$parsed_info = [];
}
else {
try {
$parsed_info = Yaml::decode(file_get_contents($filename));
} catch (InvalidDataTypeException $e) {
throw new InfoParserException("Unable to parse {$filename} " . $e->getMessage());
}
$missing_keys = array_diff($this->getRequiredKeys(), array_keys($parsed_info));
if (!empty($missing_keys)) {
throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename);
}
if (!isset($parsed_info['core_version_requirement'])) {
if (strpos($filename, 'core/') === 0 || strpos($filename, $this->root . '/core/') === 0) {
// Core extensions do not need to specify core compatibility: they are
// by definition compatible so a sensible default is used. Core
// modules are allowed to provide these for testing purposes.
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
}
elseif (isset($parsed_info['package']) && $parsed_info['package'] === 'Testing') {
// Modules in the testing package are exempt as well. This makes it
// easier for contrib to use test modules.
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
}
elseif (!isset($parsed_info['core'])) {
// Non-core extensions must specify core compatibility.
throw new InfoParserException("The 'core_version_requirement' key must be present in " . $filename);
}
}
if (isset($parsed_info['core_version_requirement'])) {
try {
$supports_pre_core_version_requirement_version = static::isConstraintSatisfiedByPreviousVersion($parsed_info['core_version_requirement'], static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION);
} catch (\UnexpectedValueException $e) {
throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) is not a valid value in {$filename}");
}
// If the 'core_version_requirement' constraint does not satisfy any
// Drupal 8 versions before 8.7.7 then 'core' cannot be set or it will
// effectively support all versions of Drupal 8 because
// 'core_version_requirement' will be ignored in previous versions.
if (!$supports_pre_core_version_requirement_version && isset($parsed_info['core'])) {
throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) requires the 'core' key not be set in " . $filename);
}
// 'core_version_requirement' can not be used to specify Drupal 8
// versions before 8.7.7 because these versions do not use the
// 'core_version_requirement' key. Do not throw the exception if the
// constraint also is satisfied by 8.0.0-alpha1 to allow constraints
// such as '^8' or '^8 || ^9'.
if ($supports_pre_core_version_requirement_version && !Semver::satisfies('8.0.0-alpha1', $parsed_info['core_version_requirement'])) {
throw new InfoParserException("The 'core_version_requirement' can not be used to specify compatibility for a specific version before " . static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION . " in {$filename}");
}
}
if (isset($parsed_info['core']) && $parsed_info['core'] !== '8.x') {
throw new InfoParserException("'core: {$parsed_info['core']}' is not supported. Use 'core_version_requirement' to specify core compatibility. Only 'core: 8.x' is supported to provide backwards compatibility for Drupal 8 when needed in {$filename}");
}
// Determine if the extension is compatible with the current version of
// Drupal core.
$core_version_constraint = $parsed_info['core_version_requirement'] ?? $parsed_info['core'];
$parsed_info['core_incompatible'] = !Semver::satisfies(\Drupal::VERSION, $core_version_constraint);
if (isset($parsed_info['version']) && $parsed_info['version'] === 'VERSION') {
$parsed_info['version'] = \Drupal::VERSION;
}
$parsed_info += [
ExtensionLifecycle::LIFECYCLE_IDENTIFIER => ExtensionLifecycle::STABLE,
];
$lifecycle = $parsed_info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
if (!ExtensionLifecycle::isValid($lifecycle)) {
$valid_values = [
ExtensionLifecycle::EXPERIMENTAL,
ExtensionLifecycle::STABLE,
ExtensionLifecycle::DEPRECATED,
ExtensionLifecycle::OBSOLETE,
];
throw new InfoParserException("'lifecycle: {$lifecycle}' is not valid in {$filename}. Valid values are: '" . implode("', '", $valid_values) . "'.");
}
if (in_array($lifecycle, [
ExtensionLifecycle::DEPRECATED,
ExtensionLifecycle::OBSOLETE,
], TRUE)) {
if (empty($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER])) {
throw new InfoParserException(sprintf("Extension %s (%s) has 'lifecycle: %s' but is missing a '%s' entry.", $parsed_info['name'], $filename, $lifecycle, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
}
if (!filter_var($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER], FILTER_VALIDATE_URL)) {
throw new InfoParserException(sprintf("Extension %s (%s) has a '%s' entry that is not a valid URL.", $parsed_info['name'], $filename, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
}
}
}
return $parsed_info;
}
/**
* Returns an array of keys required to exist in .info.yml file.
*
* @return array
* An array of required keys.
*/
protected function getRequiredKeys() {
return [
'type',
'name',
];
}
/**
* Determines if a constraint is satisfied by earlier versions of Drupal 8.
*
* @param string $constraint
* A core semantic version constraint.
* @param string $version
* A core version.
*
* @return bool
* TRUE if the constraint is satisfied by a core version prior to the
* provided version.
*/
protected static function isConstraintSatisfiedByPreviousVersion($constraint, $version) {
static $evaluated_constraints = [];
// Any particular constraint and version combination only needs to be
// evaluated once.
if (!isset($evaluated_constraints[$constraint][$version])) {
$evaluated_constraints[$constraint][$version] = FALSE;
foreach (static::getAllPreviousCoreVersions($version) as $previous_version) {
if (Semver::satisfies($previous_version, $constraint)) {
$evaluated_constraints[$constraint][$version] = TRUE;
// The constraint only has to satisfy one previous version so break
// when the first one is found.
break;
}
}
}
return $evaluated_constraints[$constraint][$version];
}
/**
* Gets all the versions of Drupal 8 before a specific version.
*
* @param string $version
* The version to get versions before.
*
* @return array
* All of the applicable Drupal 8 releases.
*/
protected static function getAllPreviousCoreVersions($version) {
static $versions_lists = [];
// Check if list of previous versions for the specified version has already
// been created.
if (empty($versions_lists[$version])) {
// Loop through all minor versions including 8.7.
foreach (range(0, 7) as $minor) {
// The largest patch number in a release was 17 in 8.6.17. Use 27 to
// leave room for future security releases.
foreach (range(0, 27) as $patch) {
$patch_version = "8.{$minor}.{$patch}";
if ($patch_version === $version) {
// Reverse the order of the versions so that they will be evaluated
// from the most recent versions first.
$versions_lists[$version] = array_reverse($versions_lists[$version]);
return $versions_lists[$version];
}
if ($patch === 0) {
// If this is a '0' patch release like '8.1.0' first create the
// pre-release versions such as '8.1.0-alpha1' and '8.1.0-rc1'.
foreach ([
'alpha',
'beta',
'rc',
] as $prerelease) {
// The largest prerelease number was in 8.0.0-beta16.
foreach (range(0, 16) as $prerelease_number) {
$versions_lists[$version][] = "{$patch_version}-{$prerelease}{$prerelease_number}";
}
}
}
$versions_lists[$version][] = $patch_version;
}
}
}
return $versions_lists[$version];
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
InfoParserDynamic::$root | protected | property | The root directory of the Drupal installation. | ||
InfoParserDynamic::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION | constant | The earliest Drupal version that supports the 'core_version_requirement'. | |||
InfoParserDynamic::getAllPreviousCoreVersions | protected static | function | Gets all the versions of Drupal 8 before a specific version. | ||
InfoParserDynamic::getRequiredKeys | protected | function | Returns an array of keys required to exist in .info.yml file. | ||
InfoParserDynamic::isConstraintSatisfiedByPreviousVersion | protected static | function | Determines if a constraint is satisfied by earlier versions of Drupal 8. | ||
InfoParserDynamic::parse | public | function | Parses Drupal module, theme and profile .info.yml files. | Overrides InfoParserInterface::parse | 1 |
InfoParserDynamic::__construct | public | function | InfoParserDynamic constructor. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.