notify('upgrade', ['check']))) { return TRUE; } } $checks = CRM_Utils_Hook::upgrade('check'); return $hasTrue($checks); } /** * Fill a queue with upgrade tasks. * * @return CRM_Queue_Queue */ public static function createQueue() { $queue = CRM_Queue_Service::singleton()->create([ 'type' => 'Sql', 'name' => self::QUEUE_NAME, 'reset' => TRUE, ]); foreach (self::getActiveUpgraders() as $upgrader) { /** @var \CRM_Extension_Upgrader_Interface $upgrader */ $upgrader->notify('upgrade', ['enqueue', $queue]); } CRM_Utils_Hook::upgrade('enqueue', $queue); // dev/core#1618 When Extension Upgrades are run reconcile log tables $task = new CRM_Queue_Task( [__CLASS__, 'upgradeLogTables'], [], ts('Update log tables') ); // Set weight low so that it will be run last. $queue->createItem($task, -2); return $queue; } /** * 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 []; } } /** * Sorts active extensions according to their dependencies * * @param string[] $keys * Names of all active modules * * @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(); // Ensure a stable starting order. $todoKeys = array_unique($keys); sort($todoKeys); $sorter = new \MJS\TopSort\Implementations\FixedArraySort(); foreach ($todoKeys as $key) { /** @var CRM_Extension_Info $info */ $info = $infos[$key] ?? NULL; // 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 { throw new CRM_Extension_Exception('Invalid extension key: "' . $key . '"'); } } return $sorter->sort(); } }