+ /**
+ * Update log tables following execution of extension upgrades
+ */
+ public static function upgradeLogTables() {
+ $logging = new CRM_Logging_Schema();
+ $logging->fixSchemaDifferences();
+ return TRUE;
+ }
+
+ /**
+ * @return array
+ * Array(string $extKey => CRM_Extension_Upgrader_Interface $upgrader)
+ */
+ protected static function getActiveUpgraders() {
+ $mapper = \CRM_Extension_System::singleton()->getMapper();
+ $keys = self::getActiveKeys();
+
+ $upgraders = [];
+ foreach ($keys as $key) {
+ $upgrader = $mapper->getUpgrader($key);
+ if ($upgrader !== NULL) {
+ $upgraders[$key] = $upgrader;
+ }
+ }
+ return $upgraders;
+ }
+
+ /**
+ * @return string[]
+ */
+ protected static function getActiveKeys() {
+ $mapper = \CRM_Extension_System::singleton()->getMapper();
+ try {
+ return self::sortKeys(array_column($mapper->getActiveModuleFiles(), 'fullName'));
+ }
+ catch (CircularDependencyException $e) {
+ CRM_Core_Error::debug_log_message("Failed to identify extensions. Circular dependency. " . $e->getMessage());
+ return [];
+ }
+ catch (ElementNotFoundException $e) {
+ CRM_Core_Error::debug_log_message("Failed to identify extensions. Unrecognized dependency. " . $e->getMessage());
+ return [];
+ }
+ }
+
+ /**
+ * @param string[] $keys
+ *
+ * @return string[]
+ * @throws \CRM_Extension_Exception
+ * @throws \MJS\TopSort\CircularDependencyException
+ * @throws \MJS\TopSort\ElementNotFoundException
+ */
+ protected static function sortKeys($keys) {
+ $infos = CRM_Extension_System::singleton()->getMapper()->getAllInfos();
+
+ // Start with our inputs in a normalized form.
+ $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;
+
+ /** @var CRM_Extension_Info $info */
+ $info = @$infos[$key];
+
+ if ($info && $info->requires) {
+ $sorter->add($key, $info->requires);
+ $todoKeys = array_merge($todoKeys, $info->requires);
+ }
+ else {
+ $sorter->add($key, []);
+ }
+ }
+ return $sorter->sort();
+ }
+