APIv4 - Add Address::getCoordinates action
[civicrm-core.git] / CRM / Extension / Upgrades.php
index adf3b1f49493501cda107cf59bf5654b2b772694..6d5991fa55b1a87cab6c6dd9ccee299b14f5bd31 100644 (file)
@@ -127,7 +127,10 @@ class CRM_Extension_Upgrades {
   }
 
   /**
+   * Sorts active extensions according to their dependencies
+   *
    * @param string[] $keys
+   *   Names of all active modules
    *
    * @return string[]
    * @throws \CRM_Extension_Exception
@@ -137,30 +140,25 @@ class CRM_Extension_Upgrades {
   protected static function sortKeys($keys) {
     $infos = CRM_Extension_System::singleton()->getMapper()->getAllInfos();
 
-    // Start with our inputs in a normalized form.
+    // Ensure a stable starting order.
     $todoKeys = array_unique($keys);
     sort($todoKeys);
 
-    // Goal: Add all active items to $sorter and flag $doneKeys['org.example.foobar']=1.
-    $doneKeys = [];
     $sorter = new \MJS\TopSort\Implementations\FixedArraySort();
 
-    while (!empty($todoKeys)) {
-      $key = array_shift($todoKeys);
-      if (isset($doneKeys[$key])) {
-        continue;
-      }
-      $doneKeys[$key] = 1;
-
+    foreach ($todoKeys as $key) {
       /** @var CRM_Extension_Info $info */
-      $info = @$infos[$key];
+      $info = $infos[$key] ?? NULL;
 
-      if ($info && $info->requires) {
-        $sorter->add($key, $info->requires);
-        $todoKeys = array_merge($todoKeys, $info->requires);
+      // Add dependencies
+      if ($info) {
+        // Filter out missing dependencies; missing modules cannot be upgraded
+        $requires = array_intersect($info->requires ?? [], $keys);
+        $sorter->add($key, $requires);
       }
+      // This shouldn't ever happen if this function is being passed a list of active extensions.
       else {
-        $sorter->add($key, []);
+        throw new CRM_Extension_Exception('Invalid extension key: "' . $key . '"');
       }
     }
     return $sorter->sort();