*/
private $coreVersion = false;
+ /**
+ * @var Constraint|bool representing PHP version
+ */
+ private $phpVersion = false;
+
+ /**
+ * @var string[] List of installed PHP extensions
+ */
+ private $phpExtensions = [];
+
+ /**
+ * @var bool[] List of provided abilities
+ */
+ private $abilities = [];
+
+ /**
+ * @var string[] List of provided ability errors
+ */
+ private $abilityErrors = [];
+
/**
* @var array Loaded extensions
*/
/**
* @param string $coreVersion Current version of core
+ * @param string $phpVersion Current PHP version
+ * @param string[] $phpExtensions List of installed PHP extensions
+ * @param bool[] $abilities List of provided abilities
+ * @param string[] $abilityErrors Error messages for the abilities
*/
- public function __construct( $coreVersion ) {
+ public function __construct(
+ $coreVersion, $phpVersion, array $phpExtensions,
+ array $abilities = [], array $abilityErrors = []
+ ) {
$this->versionParser = new VersionParser();
$this->setCoreVersion( $coreVersion );
+ $this->setPhpVersion( $phpVersion );
+ $this->phpExtensions = $phpExtensions;
+ $this->abilities = $abilities;
+ $this->abilityErrors = $abilityErrors;
}
/**
}
}
+ /**
+ * Set PHP version.
+ *
+ * @param string $phpVersion Current PHP version. Must be well-formed.
+ * @throws UnexpectedValueException
+ */
+ private function setPhpVersion( $phpVersion ) {
+ // normalize to make this throw an exception if the version is invalid
+ $this->phpVersion = new Constraint(
+ '==',
+ $this->versionParser->normalize( $phpVersion )
+ );
+ $this->phpVersion->setPrettyString( $phpVersion );
+ }
+
/**
* Check all given dependencies if they are compatible with the named
* installed extensions in the $credits array.
* {
* 'FooBar' => {
* 'MediaWiki' => '>= 1.25.0',
+ * 'platform': {
+ * 'php': '>= 7.0.0',
+ * 'ext-foo': '*',
+ * 'ability-bar': true
+ * },
* 'extensions' => {
* 'FooBaz' => '>= 1.25.0'
* },
foreach ( $dependencies as $dependencyType => $values ) {
switch ( $dependencyType ) {
case ExtensionRegistry::MEDIAWIKI_CORE:
- $mwError = $this->handleMediaWikiDependency( $values, $extension );
+ $mwError = $this->handleDependency(
+ $this->coreVersion,
+ $values,
+ $extension
+ );
if ( $mwError !== false ) {
$errors[] = [
- 'msg' => $mwError,
+ 'msg' =>
+ "{$extension} is not compatible with the current MediaWiki "
+ . "core (version {$this->coreVersion->getPrettyString()}), "
+ . "it requires: $values."
+ ,
'type' => 'incompatible-core',
];
}
break;
+ case 'platform':
+ foreach ( $values as $dependency => $constraint ) {
+ if ( $dependency === 'php' ) {
+ // PHP version
+ $phpError = $this->handleDependency(
+ $this->phpVersion,
+ $constraint,
+ $extension
+ );
+ if ( $phpError !== false ) {
+ $errors[] = [
+ 'msg' =>
+ "{$extension} is not compatible with the current PHP "
+ . "version {$this->phpVersion->getPrettyString()}), "
+ . "it requires: $constraint."
+ ,
+ 'type' => 'incompatible-php',
+ ];
+ }
+ } elseif ( substr( $dependency, 0, 4 ) === 'ext-' ) {
+ // PHP extensions
+ $phpExtension = substr( $dependency, 4 );
+ if ( $constraint !== '*' ) {
+ throw new UnexpectedValueException( 'Version constraints for '
+ . 'PHP extensions are not supported in ' . $extension );
+ }
+ if ( !in_array( $phpExtension, $this->phpExtensions, true ) ) {
+ $errors[] = [
+ 'msg' =>
+ "{$extension} requires {$phpExtension} PHP extension "
+ . "to be installed."
+ ,
+ 'type' => 'missing-phpExtension',
+ 'missing' => $phpExtension,
+ ];
+ }
+ } elseif ( substr( $dependency, 0, 8 ) === 'ability-' ) {
+ // Other abilities the environment might provide.
+ $ability = substr( $dependency, 8 );
+ if ( !isset( $this->abilities[$ability] ) ) {
+ throw new UnexpectedValueException( 'Dependency type '
+ . $dependency . ' unknown in ' . $extension );
+ }
+ if ( !is_bool( $constraint ) ) {
+ throw new UnexpectedValueException( 'Only booleans are '
+ . 'allowed to to indicate the presence of abilities '
+ . 'in ' . $extension );
+ }
+
+ if ( $constraint === true &&
+ $this->abilities[$ability] !== true
+ ) {
+ // add custom error message for missing ability if specified
+ $customMessage = '';
+ if ( isset( $this->abilityErrors[$ability] ) ) {
+ $customMessage = ': ' . $this->abilityErrors[$ability];
+ }
+
+ $errors[] = [
+ 'msg' =>
+ "{$extension} requires \"{$ability}\" ability"
+ . $customMessage
+ ,
+ 'type' => 'missing-ability',
+ 'missing' => $ability,
+ ];
+ }
+ } else {
+ // add other platform dependencies here
+ throw new UnexpectedValueException( 'Dependency type ' . $dependency .
+ ' unknown in ' . $extension );
+ }
+ }
+ break;
case 'extensions':
case 'skins':
foreach ( $values as $dependency => $constraint ) {
}
/**
- * Handle a dependency to MediaWiki core. It will check, if a MediaWiki version constraint was
- * set with self::setCoreVersion before this call (if not, it will return an empty array) and
- * checks the version constraint given against it.
+ * Handle a simple dependency to MediaWiki core or PHP. See handleMediaWikiDependency and
+ * handlePhpDependency for details.
*
+ * @param Constraint|bool $version The version installed
* @param string $constraint The required version constraint for this dependency
* @param string $checkedExt The Extension, which depends on this dependency
- * @return bool|string false if no error, or a string with the message
+ * @return bool false if no error, true else
*/
- private function handleMediaWikiDependency( $constraint, $checkedExt ) {
- if ( $this->coreVersion === false ) {
- // Couldn't parse the core version, so we can't check anything
+ private function handleDependency( $version, $constraint, $checkedExt ) {
+ if ( $version === false ) {
+ // Couldn't parse the version, so we can't check anything
return false;
}
// if the installed and required version are compatible, return an empty array
if ( $this->versionParser->parseConstraints( $constraint )
- ->matches( $this->coreVersion ) ) {
+ ->matches( $version ) ) {
return false;
}
- // otherwise mark this as incompatible.
- return "{$checkedExt} is not compatible with the current "
- . "MediaWiki core (version {$this->coreVersion->getPrettyString()}), it requires: "
- . "$constraint.";
+
+ return true;
}
/**