registration: Allow specifying extension dependencies
[lhc/web/wiklou.git] / includes / registration / VersionChecker.php
index b61a10e..2a9401e 100644 (file)
@@ -35,6 +35,11 @@ class VersionChecker {
         */
        private $coreVersion = false;
 
+       /**
+        * @var array Loaded extensions
+        */
+       private $loaded = [];
+
        /**
         * @var VersionParser
         */
@@ -44,6 +49,18 @@ class VersionChecker {
                $this->versionParser = new VersionParser();
        }
 
+       /**
+        * Set an array with credits of all loaded extensions and skins.
+        *
+        * @param array $credits An array of installed extensions with credits of them
+        * @return VersionChecker $this
+        */
+       public function setLoadedExtensionsAndSkins( array $credits ) {
+               $this->loaded = $credits;
+
+               return $this;
+       }
+
        /**
         * Set MediaWiki core version.
         *
@@ -71,7 +88,13 @@ class VersionChecker {
         * Example $extDependencies:
         *      {
         *              'GoogleAPIClient' => {
-        *                      'MediaWiki' => '>= 1.25.0'
+        *                      'MediaWiki' => '>= 1.25.0',
+        *                      'extensions' => {
+        *                              'FakeExtension' => '>= 1.25.0'
+        *                      },
+        *          'skins' => {
+        *              'FakeSkin' => '>= 1.0.0'
+        *          }
         *              }
         *      }
         *
@@ -89,6 +112,15 @@ class VersionChecker {
                                                        $this->handleMediaWikiDependency( $values, $extension )
                                                );
                                                break;
+                                       case 'extensions':
+                                       case 'skin':
+                                               foreach ( $values as $dependency => $constraint ) {
+                                                       $errors = array_merge(
+                                                               $errors,
+                                                               $this->handleExtensionDependency( $dependency, $constraint, $extension )
+                                                       );
+                                               }
+                                               break;
                                        default:
                                                throw new UnexpectedValueException( 'Dependency type ' . $dependencyType .
                                                        ' unknown in ' . $extension );
@@ -125,4 +157,58 @@ class VersionChecker {
                         . "MediaWiki core (version {$this->coreVersion->getPrettyString()}), it requires: "
                         . $constraint . '.' ];
        }
+
+       /**
+        * Handle a dependency to another extension.
+        *
+        * @param string $dependencyName The name of the dependency
+        * @param string $constraint The required version constraint for this dependency
+        * @param string $checkedExt The Extension, which depends on this dependency
+        * @return array An empty array, if installed version is compatible with $constraint, an array
+        *  with an error message, otherwise.
+        */
+       private function handleExtensionDependency( $dependencyName, $constraint, $checkedExt ) {
+               $incompatible = [];
+               // Check if the dependency is even installed
+               if ( !isset( $this->loaded[$dependencyName] ) ) {
+                       $incompatible[] = "{$checkedExt} requires {$dependencyName} to be installed.";
+                       return $incompatible;
+               }
+               // Check if the dependency has specified a version
+               if ( !isset( $this->loaded[$dependencyName]['version'] ) ) {
+                       // If we depend upon any version, and none is set, that's fine.
+                       if ( $constraint === '*' ) {
+                               wfDebug( "{$dependencyName} does not expose it's version, but {$checkedExt}
+                                       mentions it with constraint '*'. Assume it's ok so." );
+                       } else {
+                               // Otherwise, mark it as incompatible.
+                               $incompatible[] = "{$dependencyName} does not expose it's version, but {$checkedExt}
+                                       requires: {$constraint}.";
+                       }
+               } else {
+                       // Try to get a constraint for the dependency version
+                       try {
+                               $installedVersion = new Constraint(
+                                       '==',
+                                       $this->versionParser->normalize( $this->loaded[$dependencyName]['version'] )
+                               );
+                       } catch ( UnexpectedValueException $e ) {
+                               // Non-parsable version, don't fatal, output an error message that the version
+                               // string is invalid
+                               return [ "Dependency $dependencyName provides an invalid version string." ];
+                       }
+                       // Check if the constraint actually matches...
+                       if (
+                               isset( $installedVersion ) &&
+                               !$this->versionParser->parseConstraints( $constraint )->matches( $installedVersion )
+                       ) {
+                               $incompatible[] = "{$checkedExt} is not compatible with the current "
+                                       . "installed version of {$dependencyName} "
+                                       . "({$this->loaded[$dependencyName]['version']}), "
+                                       . "it requires: " . $constraint . '.';
+                       }
+               }
+
+               return $incompatible;
+       }
 }