mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 14:18:27 +01:00
Enh improve module migrations (#6550)
* Implement MigrationService: Return and log migration result during enabling, disabling and updating * Cleanup MIGRATE-DEV.md * Add `hasMigrations(Pending)()`
This commit is contained in:
parent
5d8795fca8
commit
4d142b002b
@ -3,6 +3,8 @@ HumHub Changelog
|
||||
|
||||
1.16.0 (Unreleased)
|
||||
-------------------
|
||||
- Enh #6550: Improve module migrations
|
||||
- Fix #6237: Migration errors during module activation are ignored
|
||||
- Enh #6711: run migrations manually
|
||||
- Enh #6720: Consolidate `isInstalled()`, `setInstalled()`, and `setDatabaseInstalled`
|
||||
- Fix #6693: `MigrateController::$migrationPathMap` stored rolling sum of migrations
|
||||
|
@ -8,11 +8,12 @@ Version 1.16 (Unreleased)
|
||||
-------------------------
|
||||
|
||||
### Deprecations
|
||||
- `\humhub\components\Module::migrate()` use `getMigrationService()->migrateUp(MigrationService::ACTION_MIGRATE)` instead
|
||||
- `\humhub\libs\BaseSettingsManager::isDatabaseInstalled()` use `Yii::$app->isDatabaseInstalled()` instead
|
||||
- `\humhub\models\Setting::isInstalled()` use `Yii::$app->isInstalled()` instead
|
||||
- `\humhub\modules\content\components\ContentAddonActiveRecord::canRead()` use `canView()` instead
|
||||
- `\humhub\modules\content\components\ContentAddonActiveRecord::canWrite()`
|
||||
- `\humhub\modules\file\models\File::canRead()` use `canView()` instead
|
||||
- `\humhub\modules\content\components\ContentAddonActiveRecord::canRead()` use `canView()` instead
|
||||
- `\humhub\models\Setting::isInstalled()` use `Yii::$app->isInstalled()` instead
|
||||
- `\humhub\libs\BaseSettingsManager::isDatabaseInstalled()` use `Yii::$app->isDatabaseInstalled()` instead
|
||||
|
||||
### Type restrictions
|
||||
- `\humhub\components\behaviors\PolymorphicRelation` enforces types on fields, method parameters, & return types
|
||||
|
@ -10,8 +10,8 @@ namespace humhub\commands;
|
||||
|
||||
use humhub\components\Module;
|
||||
use humhub\helpers\DatabaseHelper;
|
||||
use humhub\services\MigrationService;
|
||||
use Yii;
|
||||
use yii\base\InvalidRouteException;
|
||||
use yii\console\Exception;
|
||||
use yii\db\MigrationInterface;
|
||||
use yii\web\Application;
|
||||
@ -207,20 +207,14 @@ class MigrateController extends \yii\console\controllers\MigrateController
|
||||
* @param \yii\base\Module|null $module Module to get the migrations from, or Null for Application
|
||||
*
|
||||
* @return string output
|
||||
* @throws Exception
|
||||
* @throws InvalidRouteException
|
||||
* @deprecated since 1.16; use MigrationService::migrateUp()
|
||||
* @see MigrationService::migrateUp()
|
||||
*/
|
||||
public static function webMigrateAll(string $action = 'up', ?\yii\base\Module $module = null): string
|
||||
{
|
||||
ob_start();
|
||||
$controller = new self('migrate', $module ?? Yii::$app);
|
||||
$controller->db = Yii::$app->db;
|
||||
$controller->interactive = false;
|
||||
$controller->includeModuleMigrations = true;
|
||||
$controller->color = false;
|
||||
$controller->runAction($action);
|
||||
|
||||
return ob_get_clean() ?: '';
|
||||
return $action === 'up'
|
||||
? MigrationService::create($module)->migrateUp()
|
||||
: MigrationService::create($module)->migrateNew();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,8 +223,11 @@ class MigrateController extends \yii\console\controllers\MigrateController
|
||||
* @param string $migrationPath
|
||||
*
|
||||
* @return string output
|
||||
* @deprecated since 1.16; use MigrationService::create($module)->migrateUp()
|
||||
* @see MigrationService::create()
|
||||
* @see MigrationService::migrateUp()
|
||||
*/
|
||||
public static function webMigrateUp(string $migrationPath): string
|
||||
public static function webMigrateUp(string $migrationPath): ?string
|
||||
{
|
||||
ob_start();
|
||||
$controller = new self('migrate', Yii::$app);
|
||||
@ -240,7 +237,7 @@ class MigrateController extends \yii\console\controllers\MigrateController
|
||||
$controller->color = false;
|
||||
$controller->runAction('up');
|
||||
|
||||
return ob_get_clean() ?: '';
|
||||
return ob_get_clean() ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
@ -16,7 +16,11 @@ use humhub\modules\file\libs\FileHelper;
|
||||
use humhub\modules\marketplace\models\Module as OnlineModelModule;
|
||||
use humhub\modules\notification\components\BaseNotification;
|
||||
use humhub\modules\queue\helpers\QueueHelper;
|
||||
use humhub\services\MigrationService;
|
||||
use Throwable;
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\StaleObjectException;
|
||||
use yii\helpers\Json;
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
@ -239,21 +243,29 @@ class Module extends \yii\base\Module
|
||||
/**
|
||||
* Enables this module
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool|null Result of migration or null if beforeEnable() returned false (since v1.16)
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function enable()
|
||||
{
|
||||
Yii::$app->moduleManager->enable($this);
|
||||
$this->migrate();
|
||||
$result = $this->getMigrationService()->migrateUp();
|
||||
|
||||
return true;
|
||||
if ($result === false) {
|
||||
Yii::error('Could not enable module. Database Migration failed! See previous error for result.', $this->id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Yii::$app->moduleManager->enable($this);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables a module
|
||||
*
|
||||
* This should delete all data created by this module.
|
||||
* When override this method make sure to invoke call `parent::disable()` **AFTER** your implementation as
|
||||
* When overriding this method, make sure to invoke call `parent::disable()` **AFTER** your implementation as
|
||||
*
|
||||
* ```php
|
||||
* public function disable()
|
||||
@ -262,61 +274,40 @@ class Module extends \yii\base\Module
|
||||
* parent::disable();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @return bool|null Result uninstall-migration or null if beforeDisable() returned false (since v1.16)
|
||||
* @throws InvalidConfigException
|
||||
* @throws StaleObjectException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
/**
|
||||
* Remove database tables
|
||||
*/
|
||||
$migrationPath = $this->getBasePath() . '/migrations';
|
||||
$uninstallMigration = $migrationPath . '/uninstall.php';
|
||||
if (file_exists($uninstallMigration)) {
|
||||
|
||||
/**
|
||||
* Execute Uninstall Migration
|
||||
*/
|
||||
ob_start();
|
||||
require_once($uninstallMigration);
|
||||
$migration = new \uninstall;
|
||||
try {
|
||||
$migration->up();
|
||||
} catch (\yii\db\Exception $ex) {
|
||||
Yii::error($ex);
|
||||
}
|
||||
ob_get_clean();
|
||||
|
||||
/**
|
||||
* Delete all Migration Table Entries
|
||||
*/
|
||||
$migrations = opendir($migrationPath);
|
||||
$params = [];
|
||||
while (false !== ($migration = readdir($migrations))) {
|
||||
if ($migration == '.' || $migration == '..' || $migration == 'uninstall.php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$command ??= Yii::$app->db->createCommand()->delete('migration', 'version = :version', $params);
|
||||
|
||||
$version = str_replace('.php', '', $migration);
|
||||
$command->bindValue(':version', $version)->execute();
|
||||
}
|
||||
try {
|
||||
$result = $this->getMigrationService()->uninstall();
|
||||
ContentContainerSetting::deleteAll(['module_id' => $this->id]);
|
||||
Setting::deleteAll(['module_id' => $this->id]);
|
||||
} catch (Throwable $ex) {
|
||||
Yii::error($ex, $this->id);
|
||||
$result = false;
|
||||
}
|
||||
|
||||
ContentContainerSetting::deleteAll(['module_id' => $this->id]);
|
||||
Setting::deleteAll(['module_id' => $this->id]);
|
||||
|
||||
Yii::$app->moduleManager->disable($this);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all not applied module migrations
|
||||
* @deprecated since v1.16; use static::getMigrationService()->migrateUp()
|
||||
*/
|
||||
public function migrate()
|
||||
{
|
||||
$migrationPath = $this->basePath . '/migrations';
|
||||
if (is_dir($migrationPath)) {
|
||||
\humhub\commands\MigrateController::webMigrateUp($migrationPath);
|
||||
}
|
||||
return $this->getMigrationService()->migrateUp();
|
||||
}
|
||||
|
||||
public function getMigrationService(): MigrationService
|
||||
{
|
||||
return new MigrationService($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -342,10 +333,15 @@ class Module extends \yii\base\Module
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
if($this->beforeUpdate() !== false) {
|
||||
$this->migrate();
|
||||
$this->afterUpdate();
|
||||
if (!$this->beforeUpdate()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = $this->getMigrationService()->migrateUp();
|
||||
|
||||
$this->afterUpdate();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,13 +356,11 @@ class Module extends \yii\base\Module
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called right after the module update.
|
||||
*/
|
||||
public function afterUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -483,7 +477,7 @@ class Module extends \yii\base\Module
|
||||
$assetDirectory = $this->getBasePath() . DIRECTORY_SEPARATOR . 'assets';
|
||||
if (is_dir($assetDirectory)) {
|
||||
foreach (FileHelper::findFiles($assetDirectory, ['recursive' => false,]) as $file) {
|
||||
$assetClass = $assetNamespace . '\\' . basename($file, '.php');
|
||||
$assetClass = $assetNamespace . '\\' . basename($file, '.php');
|
||||
if (is_subclass_of($assetClass, AssetBundle::class)) {
|
||||
$assets[] = $assetClass;
|
||||
}
|
||||
|
@ -17,11 +17,14 @@ use humhub\exceptions\InvalidArgumentTypeException;
|
||||
use humhub\models\ModuleEnabled;
|
||||
use humhub\modules\admin\events\ModulesEvent;
|
||||
use humhub\modules\marketplace\Module as ModuleMarketplace;
|
||||
use Throwable;
|
||||
use Yii;
|
||||
use yii\base\Component;
|
||||
use yii\base\ErrorException;
|
||||
use yii\base\Event;
|
||||
use yii\base\Exception;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\StaleObjectException;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\helpers\FileHelper;
|
||||
|
||||
@ -131,8 +134,8 @@ class ModuleManager extends Component
|
||||
*
|
||||
* @param array $configs
|
||||
*
|
||||
* @throws InvalidConfigException
|
||||
* @see \humhub\components\bootstrap\ModuleAutoLoader::bootstrap
|
||||
* @throws InvalidConfigException Module configuration does not have both an id and class attribute
|
||||
* @see ModuleAutoLoader::bootstrap
|
||||
*
|
||||
*/
|
||||
public function registerBulk(array $configs)
|
||||
@ -145,19 +148,19 @@ class ModuleManager extends Component
|
||||
/**
|
||||
* Registers a module
|
||||
*
|
||||
* @param string $basePath the modules base path
|
||||
* @param array $config the module configuration (config.php)
|
||||
* @param string $basePath the module's base path
|
||||
* @param array|null $config the module configuration (config.php)
|
||||
*
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidConfigException Module configuration does not have both an id and class attribute
|
||||
*/
|
||||
public function register($basePath, $config = null)
|
||||
public function register(string $basePath, ?array $config = null)
|
||||
{
|
||||
if ($config === null && is_file($filename = $basePath . '/config.php')) {
|
||||
$config = include $filename;
|
||||
}
|
||||
|
||||
// Check mandatory config options
|
||||
if (!isset($config['class']) || !isset($config['id'])) {
|
||||
if (!isset($config['class'], $config['id'])) {
|
||||
throw new InvalidConfigException('Module configuration requires an id and class attribute: ' . $basePath);
|
||||
}
|
||||
|
||||
@ -345,12 +348,16 @@ class ModuleManager extends Component
|
||||
|
||||
$modules = [];
|
||||
foreach ($this->modules as $id => $class) {
|
||||
if (!$options['includeCoreModules'] && in_array($class, $this->coreModules)) {
|
||||
if (!$options['includeCoreModules'] && in_array($class, $this->coreModules, true)) {
|
||||
// Skip core modules
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($options['enabled'] && !in_array($class, $this->coreModules) && !in_array($id, $this->enabledModules)) {
|
||||
if (
|
||||
$options['enabled']
|
||||
&& !in_array($class, $this->coreModules, true)
|
||||
&& !in_array($id, $this->enabledModules, true)
|
||||
) {
|
||||
// Skip disabled modules
|
||||
continue;
|
||||
}
|
||||
@ -568,7 +575,7 @@ class ModuleManager extends Component
|
||||
* @param bool $disableBeforeRemove
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws \yii\base\ErrorException
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public function removeModule($moduleId, $disableBeforeRemove = true): ?string
|
||||
{
|
||||
@ -624,6 +631,7 @@ class ModuleManager extends Component
|
||||
|
||||
$this->enabledModules[] = $module->id;
|
||||
$this->register($module->getBasePath());
|
||||
$this->flushCache();
|
||||
|
||||
$this->trigger(static::EVENT_AFTER_MODULE_ENABLE, new ModuleEvent(['module' => $module]));
|
||||
}
|
||||
@ -643,8 +651,8 @@ class ModuleManager extends Component
|
||||
*
|
||||
* @param Module $module
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws \yii\db\StaleObjectException
|
||||
* @throws Throwable
|
||||
* @throws StaleObjectException
|
||||
* @since 1.1
|
||||
*/
|
||||
public function disable(Module $module)
|
||||
@ -662,6 +670,8 @@ class ModuleManager extends Component
|
||||
|
||||
Yii::$app->setModule($module->id, null);
|
||||
|
||||
$this->flushCache();
|
||||
|
||||
$this->trigger(static::EVENT_AFTER_MODULE_DISABLE, new ModuleEvent(['module' => $module]));
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ abstract class SettingActiveRecord extends ActiveRecord
|
||||
* @param string|array|null $condition
|
||||
* @param array $params
|
||||
*
|
||||
* @return int
|
||||
* @return int the number of rows deleted
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
*/
|
||||
public static function deleteAll($condition = null, $params = [])
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
@ -12,6 +13,7 @@ use Yii;
|
||||
use yii\base\BootstrapInterface;
|
||||
use yii\base\ErrorException;
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\helpers\FileHelper;
|
||||
|
||||
/**
|
||||
@ -21,13 +23,16 @@ use yii\helpers\FileHelper;
|
||||
*/
|
||||
class ModuleAutoLoader implements BootstrapInterface
|
||||
{
|
||||
const CACHE_ID = 'module_configs';
|
||||
const CONFIGURATION_FILE = 'config.php';
|
||||
public const CACHE_ID = 'module_configs';
|
||||
public const CONFIGURATION_FILE = 'config.php';
|
||||
|
||||
/**
|
||||
* Bootstrap method to be called during application bootstrap stage.
|
||||
*
|
||||
* @param Application $app the application currently running
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
*
|
||||
* @throws InvalidConfigException Module a configuration does not have both an id and class attribute
|
||||
* @throws ErrorException On invalid module autoload path
|
||||
*/
|
||||
public function bootstrap($app)
|
||||
{
|
||||
@ -37,10 +42,12 @@ class ModuleAutoLoader implements BootstrapInterface
|
||||
|
||||
/**
|
||||
* Find available modules
|
||||
* @return array
|
||||
* @throws ErrorException
|
||||
*
|
||||
* @return array[] Array of module configurations with module ID as index.
|
||||
* Read from cache if available and YII_DEBUG is disabled
|
||||
* @throws ErrorException On invalid module autoload path
|
||||
*/
|
||||
public static function locateModules()
|
||||
public static function locateModules(): array
|
||||
{
|
||||
$modules = Yii::$app->cache->get(self::CACHE_ID);
|
||||
|
||||
@ -54,11 +61,13 @@ class ModuleAutoLoader implements BootstrapInterface
|
||||
|
||||
/**
|
||||
* Find all modules with configured paths
|
||||
* @param array $paths
|
||||
* @return array
|
||||
* @throws ErrorException
|
||||
*
|
||||
* @param string[] $paths
|
||||
*
|
||||
* @return array[] Array of module configurations with module ID as index
|
||||
* @throws ErrorException On invalid module autoload path
|
||||
*/
|
||||
private static function findModules($paths)
|
||||
private static function findModules(iterable $paths): array
|
||||
{
|
||||
$folders = [];
|
||||
foreach ($paths as $path) {
|
||||
@ -71,11 +80,12 @@ class ModuleAutoLoader implements BootstrapInterface
|
||||
|
||||
$modules = [];
|
||||
$moduleIdFolders = [];
|
||||
$preventDuplicatedModules = Yii::$app->moduleManager->preventDuplicatedModules;
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
try {
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$moduleConfig = include $folder . DIRECTORY_SEPARATOR . self::CONFIGURATION_FILE;
|
||||
if (Yii::$app->moduleManager->preventDuplicatedModules && isset($moduleIdFolders[$moduleConfig['id']])) {
|
||||
if ($preventDuplicatedModules && isset($moduleIdFolders[$moduleConfig['id']])) {
|
||||
Yii::error('Duplicated module "' . $moduleConfig['id'] . '"(' . $folder . ') is already loaded from the folder "' . $moduleIdFolders[$moduleConfig['id']] . '"');
|
||||
} else {
|
||||
$modules[$folder] = $moduleConfig;
|
||||
@ -86,10 +96,10 @@ class ModuleAutoLoader implements BootstrapInterface
|
||||
}
|
||||
}
|
||||
|
||||
if (Yii::$app->moduleManager->preventDuplicatedModules) {
|
||||
if ($preventDuplicatedModules) {
|
||||
// Overwrite module paths from config
|
||||
foreach (Yii::$app->moduleManager->overwriteModuleBasePath as $overwriteModuleId => $overwriteModulePath) {
|
||||
if (isset($moduleIdFolders[$overwriteModuleId]) && $moduleIdFolders[$overwriteModuleId] != $overwriteModulePath) {
|
||||
if (isset($moduleIdFolders[$overwriteModuleId]) && $moduleIdFolders[$overwriteModuleId] !== $overwriteModulePath) {
|
||||
try {
|
||||
$moduleConfig = include $overwriteModulePath . DIRECTORY_SEPARATOR . self::CONFIGURATION_FILE;
|
||||
Yii::info('Overwrite path of the module "' . $overwriteModuleId . '" to the folder "' . $overwriteModulePath . '"');
|
||||
@ -110,13 +120,15 @@ class ModuleAutoLoader implements BootstrapInterface
|
||||
|
||||
/**
|
||||
* Find all directories with a configuration file inside
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*
|
||||
* @return string[]
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private static function findModulesByPath($path)
|
||||
private static function findModulesByPath(string $path): array
|
||||
{
|
||||
$hasConfigurationFile = function ($path) {
|
||||
$hasConfigurationFile = static function ($path) {
|
||||
return is_file($path . DIRECTORY_SEPARATOR . self::CONFIGURATION_FILE);
|
||||
};
|
||||
|
||||
|
39
protected/humhub/events/MigrationEvent.php
Normal file
39
protected/humhub/events/MigrationEvent.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\events;
|
||||
|
||||
use humhub\components\Event;
|
||||
use humhub\interfaces\ApplicationInterface;
|
||||
use yii\base\Module;
|
||||
|
||||
/**
|
||||
* @property int|null $result Result of the migration:
|
||||
* ``
|
||||
* - `ExitCode::OK`: Success;
|
||||
* - `ExitCode::UNSPECIFIED_ERROR`: failure;
|
||||
* - `Null`: nothing done
|
||||
* ``
|
||||
*/
|
||||
class MigrationEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var \humhub\components\Module|ApplicationInterface|null
|
||||
*/
|
||||
public ?Module $module;
|
||||
|
||||
/**
|
||||
* @var string Either `up` or `uninstall`
|
||||
*/
|
||||
public string $migration;
|
||||
|
||||
/**
|
||||
* @var string|null Output of the MigrationController's Action
|
||||
*/
|
||||
public ?string $output = null;
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
|
||||
namespace humhub\modules\admin\controllers;
|
||||
|
||||
use humhub\commands\MigrateController;
|
||||
use humhub\libs\SelfTest;
|
||||
use humhub\modules\admin\components\Controller;
|
||||
use humhub\modules\admin\components\DatabaseInfo;
|
||||
@ -18,6 +17,7 @@ use humhub\modules\queue\driver\MySQL;
|
||||
use humhub\modules\queue\helpers\QueueHelper;
|
||||
use humhub\modules\queue\interfaces\QueueInfoInterface;
|
||||
use humhub\modules\search\jobs\RebuildIndex;
|
||||
use humhub\services\MigrationService;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Yii;
|
||||
@ -89,18 +89,21 @@ class InformationController extends Controller
|
||||
|
||||
public function actionDatabase(int $migrate = self::DB_ACTION_CHECK)
|
||||
{
|
||||
$migrationService = MigrationService::create();
|
||||
|
||||
if ($migrate === self::DB_ACTION_RUN) {
|
||||
$migrationService->migrateUp();
|
||||
$migrationOutput = sprintf(
|
||||
"%s\n%s",
|
||||
MigrateController::webMigrateAll(),
|
||||
$migrationService->getLastMigrationOutput(),
|
||||
SettingController::flushCache()
|
||||
);
|
||||
} else {
|
||||
$migrationOutput = MigrateController::webMigrateAll(MigrateController::MIGRATION_ACTION_NEW);
|
||||
$migrate = $migrationService->hasMigrationsPending()
|
||||
? self::DB_ACTION_PENDING
|
||||
: self::DB_ACTION_CHECK;
|
||||
|
||||
$migrate = str_contains($migrationOutput, 'No new migrations found.')
|
||||
? self::DB_ACTION_CHECK
|
||||
: self::DB_ACTION_PENDING;
|
||||
$migrationOutput = $migrationService->getLastMigrationOutput();
|
||||
}
|
||||
|
||||
$databaseInfo = new DatabaseInfo(Yii::$app->db->dsn);
|
||||
|
@ -28,7 +28,7 @@ class ContentContainerModule extends Module
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function disable()
|
||||
public function disable(): ?bool
|
||||
{
|
||||
// disable in content containers
|
||||
$contentContainerQuery = ContentContainerModuleManager::getContentContainerQueryByModule($this->id);
|
||||
@ -41,7 +41,7 @@ class ContentContainerModule extends Module
|
||||
$moduleState->delete();
|
||||
}
|
||||
|
||||
parent::disable();
|
||||
return parent::disable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
namespace humhub\modules\installer\commands;
|
||||
|
||||
use humhub\commands\MigrateController;
|
||||
use humhub\helpers\DatabaseHelper;
|
||||
use humhub\libs\DynamicConfig;
|
||||
use humhub\libs\UUID;
|
||||
@ -16,6 +15,7 @@ use humhub\modules\installer\libs\InitialData;
|
||||
use humhub\modules\user\models\Group;
|
||||
use humhub\modules\user\models\Password;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\services\MigrationService;
|
||||
use Yii;
|
||||
use yii\base\Exception;
|
||||
use yii\console\Controller;
|
||||
@ -89,9 +89,8 @@ class InstallController extends Controller
|
||||
$this->stdout(" * Installing Database\n", Console::FG_YELLOW);
|
||||
|
||||
Yii::$app->cache->flush();
|
||||
// Disable max execution time to avoid timeouts during migrations
|
||||
@ini_set('max_execution_time', 0);
|
||||
MigrateController::webMigrateAll();
|
||||
|
||||
MigrationService::create()->migrateUp();
|
||||
|
||||
DynamicConfig::rewrite();
|
||||
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
namespace humhub\modules\installer\controllers;
|
||||
|
||||
use humhub\commands\MigrateController;
|
||||
use humhub\components\access\ControllerAccess;
|
||||
use humhub\components\Controller;
|
||||
use humhub\libs\DynamicConfig;
|
||||
use humhub\modules\admin\widgets\PrerequisitesList;
|
||||
use humhub\modules\installer\forms\DatabaseForm;
|
||||
use humhub\modules\installer\Module;
|
||||
use humhub\services\MigrationService;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
@ -183,11 +183,8 @@ class SetupController extends Controller
|
||||
// Flush Caches
|
||||
Yii::$app->cache->flush();
|
||||
|
||||
// Disable max execution time to avoid timeouts during database installation
|
||||
@ini_set('max_execution_time', 0);
|
||||
|
||||
// Migrate Up Database
|
||||
MigrateController::webMigrateAll();
|
||||
MigrationService::create()->migrateUp();
|
||||
|
||||
DynamicConfig::rewrite();
|
||||
|
||||
|
@ -173,7 +173,7 @@ class OnlineModuleManager extends Component
|
||||
$this->install($moduleId);
|
||||
|
||||
$updatedModule = Yii::$app->moduleManager->getModule($moduleId);
|
||||
$updatedModule->migrate();
|
||||
$updatedModule->getMigrationService()->migrateUp();
|
||||
|
||||
(new MarketplaceService())->refreshPendingModuleUpdateCount();
|
||||
|
||||
|
339
protected/humhub/services/MigrationService.php
Normal file
339
protected/humhub/services/MigrationService.php
Normal file
@ -0,0 +1,339 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\services;
|
||||
|
||||
use humhub\commands\MigrateController;
|
||||
use humhub\components\Application;
|
||||
use humhub\components\Event;
|
||||
use humhub\components\Module;
|
||||
use humhub\events\MigrationEvent;
|
||||
use humhub\interfaces\ApplicationInterface;
|
||||
use humhub\libs\Helpers;
|
||||
use Throwable;
|
||||
use Yii;
|
||||
use yii\base\ActionEvent;
|
||||
use yii\base\Component;
|
||||
use yii\base\Controller;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\Module as BaseModule;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
/**
|
||||
* @since 1.16
|
||||
*/
|
||||
class MigrationService extends Component
|
||||
{
|
||||
public const EVENT_AFTER_MIGRATION = 'afterMigration';
|
||||
protected const MIGRATION_NEW = 'new';
|
||||
protected const MIGRATION_UNINSTALL = 'uninstall';
|
||||
protected const MIGRATION_UP = 'up';
|
||||
|
||||
protected BaseModule $module;
|
||||
private ?string $path;
|
||||
private ?int $lastMigrationResult = null;
|
||||
private ?string $lastMigrationOutput = null;
|
||||
|
||||
/**
|
||||
* @param Module|ApplicationInterface|Application|null $module
|
||||
*/
|
||||
public function __construct(?BaseModule $module = null)
|
||||
{
|
||||
Helpers::checkClassType($module, [ApplicationInterface::class, Module::class, null]);
|
||||
|
||||
$this->module = $module ?? Yii::$app;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
/**
|
||||
* Since for console application the id is set to 'humhub-console' and might be configured for the application too,
|
||||
* we need to use the hard-coded 'humhub' string for non-modules.
|
||||
*
|
||||
* @see \humhub\components\console\Application::$id
|
||||
* @see protected/humhub/config/console.php
|
||||
*/
|
||||
$moduleId = $this->module instanceof Module
|
||||
? $this->module->id
|
||||
: 'humhub';
|
||||
|
||||
$this->path = "@$moduleId/migrations";
|
||||
|
||||
$realpath = $this->getPath(true);
|
||||
|
||||
if ($realpath === false || !is_dir($realpath)) {
|
||||
Yii::debug("Module has no migrations directory.", $this->module->id);
|
||||
$this->path = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Module|ApplicationInterface|Application|null
|
||||
*/
|
||||
public function getModule(): BaseModule
|
||||
{
|
||||
return $this->module;
|
||||
}
|
||||
|
||||
private function getPath(bool $resolve = false): ?string
|
||||
{
|
||||
if (!$resolve || $this->path === null) {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
$path = realpath(Yii::getAlias($this->path));
|
||||
|
||||
if ($path === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function getLastMigrationOutput(): ?string
|
||||
{
|
||||
return $this->lastMigrationOutput;
|
||||
}
|
||||
|
||||
public function getLastMigrationResult(): ?int
|
||||
{
|
||||
return $this->lastMigrationResult;
|
||||
}
|
||||
|
||||
public function hasMigrations(): bool
|
||||
{
|
||||
return $this->path !== null;
|
||||
}
|
||||
|
||||
public function hasMigrationsPending(): bool
|
||||
{
|
||||
if (!$this->hasMigrations()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->migrateNew() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$migrationOutput = $this->getLastMigrationOutput();
|
||||
|
||||
return !str_contains($migrationOutput, 'No new migrations found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run migrations.
|
||||
*/
|
||||
public function migrateNew(): ?bool
|
||||
{
|
||||
return $this->migrate(MigrationService::MIGRATION_NEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for pending migrations
|
||||
*/
|
||||
public function migrateUp(): ?bool
|
||||
{
|
||||
return $this->migrate(MigrationService::MIGRATION_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action Must be MigrationService::MIGRATION_ACTION_UP to run migrations,
|
||||
* or MigrationService::MIGRATION_ACTION_NEW to check for pending migrations
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
private function migrate(string $action): ?bool
|
||||
{
|
||||
$result = $this->checkMigrationBefore($action);
|
||||
|
||||
if ($result === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// this event is collecting the migration's result status and storing it in our event
|
||||
Event::on(
|
||||
MigrateController::class,
|
||||
Controller::EVENT_AFTER_ACTION,
|
||||
[
|
||||
$this,
|
||||
'onMigrationControllerAfterAction'
|
||||
],
|
||||
$result
|
||||
);
|
||||
|
||||
// Disable max execution time to avoid timeouts during migrations
|
||||
@ini_set('max_execution_time', 0);
|
||||
|
||||
$module = $this->getModule();
|
||||
|
||||
ob_start();
|
||||
$controller = new MigrateController('migrate', $module, [
|
||||
'db' => Yii::$app->db,
|
||||
'interactive' => false,
|
||||
'color' => false,
|
||||
'migrationPath' => $this->getPath(),
|
||||
'includeModuleMigrations' => true,
|
||||
]);
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$controller->runAction($action);
|
||||
|
||||
$result->output = ob_get_clean() ?: null;
|
||||
|
||||
// we no longer need to listen to this event
|
||||
Event::off(
|
||||
MigrateController::class,
|
||||
Controller::EVENT_AFTER_ACTION,
|
||||
[
|
||||
$this,
|
||||
'onMigrationControllerAfterAction'
|
||||
]
|
||||
);
|
||||
|
||||
return $this->checkMigrationStatus($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catches migration results.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function onMigrationControllerAfterAction(ActionEvent $event)
|
||||
{
|
||||
if (!$event->sender instanceof MigrateController) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$event->data instanceof MigrationEvent || $event->data->sender !== $this) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->data->result = $event->result ?? ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
|
||||
private function checkMigrationBefore(string $migrationAction): ?MigrationEvent
|
||||
{
|
||||
$this->lastMigrationOutput = null;
|
||||
$this->lastMigrationResult = null;
|
||||
|
||||
if (!$this->hasMigrations()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MigrationEvent([
|
||||
'sender' => $this,
|
||||
'module' => $this->getModule(),
|
||||
'migration' => $migrationAction,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MigrationEvent $result
|
||||
*
|
||||
* @return bool
|
||||
* @throws InvalidConfigException
|
||||
* @throws Throwable
|
||||
*/
|
||||
private function checkMigrationStatus(MigrationEvent $result): bool
|
||||
{
|
||||
$this->lastMigrationOutput = $result->output ?: 'Migration output unavailable';
|
||||
$this->lastMigrationResult = $result->result;
|
||||
|
||||
/** @see \yii\console\controllers\BaseMigrateController::actionUp() */
|
||||
if ($result->result > ExitCode::OK) {
|
||||
Yii::error($this->lastMigrationOutput, $this->module->id);
|
||||
} else {
|
||||
Yii::info($this->lastMigrationOutput, $this->module->id);
|
||||
}
|
||||
|
||||
$this->trigger(self::EVENT_AFTER_MIGRATION, $result);
|
||||
|
||||
/** @see \yii\console\controllers\BaseMigrateController::actionUp() */
|
||||
if ($result->result > ExitCode::OK) {
|
||||
$errorMessage = "Migration failed!";
|
||||
|
||||
if (YII_DEBUG) {
|
||||
throw new InvalidConfigException($errorMessage);
|
||||
}
|
||||
|
||||
Yii::error($errorMessage, $this->module->id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function uninstall(): ?bool
|
||||
{
|
||||
$result = $this->checkMigrationBefore(self::MIGRATION_UNINSTALL);
|
||||
|
||||
if ($result === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = $this->getPath(true);
|
||||
$uninstallMigration = $path . '/uninstall.php';
|
||||
|
||||
if (!file_exists($uninstallMigration)) {
|
||||
Yii::warning("Module has no uninstall migration!", $this->module->id);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Uninstall Migration
|
||||
*/
|
||||
ob_start();
|
||||
require_once($uninstallMigration);
|
||||
|
||||
$migration = new \uninstall();
|
||||
$migration->compact = false;
|
||||
|
||||
try {
|
||||
$result->result = $migration->up() === false ? ExitCode::UNSPECIFIED_ERROR : ExitCode::OK;
|
||||
} catch (\yii\db\Exception $ex) {
|
||||
Yii::error($ex, $this->module->id);
|
||||
$result->result = ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
$result->output = ob_get_clean();
|
||||
|
||||
/**
|
||||
* Delete all Migration Table Entries
|
||||
*/
|
||||
$migrations = opendir($path);
|
||||
$params = [];
|
||||
while (false !== ($migration = readdir($migrations))) {
|
||||
if ($migration === '.' || $migration === '..' || $migration === 'uninstall.php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$command ??= Yii::$app->db->createCommand()->delete('migration', 'version = :version', $params);
|
||||
|
||||
$version = str_replace('.php', '', $migration);
|
||||
$command->bindValue(':version', $version)->execute();
|
||||
$result->output .= " > migration entry $version removed.\n";
|
||||
}
|
||||
|
||||
return $this->checkMigrationStatus($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Module|ApplicationInterface|Application|null $module
|
||||
*
|
||||
* @noinspection PhpDocMissingThrowsInspection
|
||||
*/
|
||||
public static function create(?BaseModule $module = null): self
|
||||
{
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
return Yii::createObject(static::class, [$module]);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace Some\Name\Space\moduleWithMigration;
|
||||
|
||||
class Module extends \humhub\components\Module
|
||||
{
|
||||
public const ID = 'moduleWithMigration';
|
||||
public const NAMESPACE = __NAMESPACE__;
|
||||
public bool $doEnable = true;
|
||||
public bool $doDisable = true;
|
||||
|
||||
public function beforeEnable(): bool
|
||||
{
|
||||
return $this->doEnable;
|
||||
}
|
||||
|
||||
public function beforeDisable(): bool
|
||||
{
|
||||
return $this->doDisable;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
/** @noinspection MissedFieldInspection */
|
||||
|
||||
require_once __DIR__ . "/Module.php";
|
||||
|
||||
return [
|
||||
'id' => 'moduleWithMigration',
|
||||
'class' => \Some\Name\Space\moduleWithMigration\Module::class,
|
||||
'namespace' => "Some\\Name\\Space\\moduleWithMigration",
|
||||
'events' => [
|
||||
[
|
||||
'class' => \humhub\tests\codeception\unit\components\ModuleManagerTest::class,
|
||||
'event' => 'valid',
|
||||
'callback' => [
|
||||
\humhub\tests\codeception\unit\components\ModuleManagerTest::class,
|
||||
'handleEvent',
|
||||
],
|
||||
],
|
||||
]
|
||||
];
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\components\Migration;
|
||||
|
||||
class m230911_000100_create_test_table extends Migration
|
||||
{
|
||||
// protected properties
|
||||
protected string $table = 'test_module_with_migration';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function safeUp()
|
||||
{
|
||||
$this->safeCreateTable($this->table, [
|
||||
'id' => $this->primaryKey(),
|
||||
'created_by' => $this->integerReferenceKey(),
|
||||
'created_at' => $this->timestampWithoutAutoUpdate()
|
||||
->notNull(),
|
||||
]);
|
||||
|
||||
// add foreign key for table `user`
|
||||
$this->safeAddForeignKeyCreatedBy();
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\components\Migration;
|
||||
|
||||
/**
|
||||
* Class uninstall
|
||||
*/
|
||||
class uninstall extends Migration
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function safeUp()
|
||||
{
|
||||
// enable output
|
||||
$this->compact = false;
|
||||
|
||||
$this->safeDropTable('test_module_with_migration');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function safeDown()
|
||||
{
|
||||
echo "uninstall cannot be reverted.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "example",
|
||||
"version": "1.0",
|
||||
"name": "My Example Module With Migration",
|
||||
"description": "My testing module with migration",
|
||||
"humhub": {
|
||||
"minVersion": "1.2"
|
||||
},
|
||||
"keywords": ["valid", "migration"],
|
||||
"homepage": "https://www.example.com",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tom Coder",
|
||||
"email": "tc@example.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Sarah Mustermann",
|
||||
"email": "sm@example.com",
|
||||
"homepage": "http://example.com",
|
||||
"role": "Translator"
|
||||
}
|
||||
],
|
||||
"licence": "AGPL-3.0-or-later"
|
||||
}
|
@ -19,6 +19,7 @@ use humhub\modules\admin\events\ModulesEvent;
|
||||
use humhub\tests\codeception\unit\ModuleAutoLoaderTest;
|
||||
use Some\Name\Space\module1\Module as Module1;
|
||||
use Some\Name\Space\module2\Module as Module2;
|
||||
use Some\Name\Space\moduleWithMigration\Module as ModuleWithMigration;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
use Yii;
|
||||
use yii\base\ErrorException;
|
||||
@ -26,8 +27,10 @@ use yii\base\Event;
|
||||
use yii\base\Exception;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\caching\ArrayCache;
|
||||
use yii\console\ExitCode;
|
||||
use yii\db\StaleObjectException;
|
||||
use yii\helpers\FileHelper;
|
||||
use yii\log\Logger;
|
||||
|
||||
require_once __DIR__ . '/bootstrap/ModuleAutoLoaderTest.php';
|
||||
|
||||
@ -582,7 +585,10 @@ class ModuleManagerTest extends HumHubDbTestCase
|
||||
public function testGetModules()
|
||||
{
|
||||
$moduleManager = Yii::$app->moduleManager;
|
||||
static::assertIsArray($modules = $moduleManager->getModules(['returnClass' => true]));
|
||||
|
||||
$modules = $moduleManager->getModules(['returnClass' => true]);
|
||||
|
||||
static::assertIsArray($modules);
|
||||
static::assertCount(static::$moduleDirCount, $modules);
|
||||
}
|
||||
|
||||
@ -598,13 +604,23 @@ class ModuleManagerTest extends HumHubDbTestCase
|
||||
|
||||
$module = $this->registerModule($basePath, $config);
|
||||
|
||||
$oldMM = Yii::$app->cache;
|
||||
$oldMM = Yii::$app->moduleManager;
|
||||
Yii::$app->set('moduleManager', $this->moduleManager);
|
||||
|
||||
static::logInitialize();
|
||||
|
||||
$this->moduleManager->enableModules([$module, static::$testModuleRoot . '/module2']);
|
||||
|
||||
Yii::$app->set('moduleManager', $oldMM);
|
||||
|
||||
static::assertNotLog('Module has not been enabled due to beforeEnable() returning false', Logger::LEVEL_WARNING, [$module->id]);
|
||||
static::assertLog('Module has no migrations directory.', Logger::LEVEL_TRACE, [$module->id]);
|
||||
|
||||
static::assertNotLog('Module has not been enabled due to beforeEnable() returning false', Logger::LEVEL_WARNING, ['module2']);
|
||||
static::assertLogRegex('@No new migrations found\. Your system is up-to-date\.@', Logger::LEVEL_INFO, ['module2']);
|
||||
|
||||
static::logReset();
|
||||
|
||||
/** @noinspection MissedFieldInspection */
|
||||
$this->assertEvents([
|
||||
[
|
||||
@ -633,6 +649,63 @@ class ModuleManagerTest extends HumHubDbTestCase
|
||||
$this->moduleManager->enableModules([static::$testModuleRoot . '/non-existing-module']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection MissedFieldInspection
|
||||
*/
|
||||
public function testEnableModulesWithMigration()
|
||||
{
|
||||
Yii::$app->set('moduleManager', $this->moduleManager);
|
||||
$this->moduleManager->on(ModuleManager::EVENT_AFTER_MODULE_ENABLE, [$this, 'handleEvent']);
|
||||
|
||||
/** @var ModuleWithMigration $module */
|
||||
$module = $this->moduleManager->getModule(static::$testModuleRoot . '/moduleWithMigration');
|
||||
|
||||
static::logInitialize();
|
||||
|
||||
// ToDo: beforeEnable() has been removed from this PR and will be re-introduced as an event in a follow-up PR
|
||||
// $module->doEnable = false;
|
||||
// static::assertNull($module->enable());
|
||||
// static::assertNull($module->migrationResult);
|
||||
// static::assertNull($module->migrationOutput);
|
||||
// $this->assertEvents();
|
||||
// static::assertLog('Module has not been enabled due to beforeEnable() returning false', Logger::LEVEL_WARNING, [$module->id]);
|
||||
// static::logFlush();
|
||||
|
||||
$module->doEnable = true;
|
||||
static::assertTrue($module->enable());
|
||||
// static::assertEquals(ExitCode::OK, $module->migrationResult);
|
||||
// static::assertNotLog('Module has not been enabled due to beforeEnable() returning false', Logger::LEVEL_WARNING, [$module->id]);
|
||||
// static::assertLogRegex('@\*\*\* applied m230911_000100_create_test_table \(time: \d+\.\d+s\)@', Logger::LEVEL_INFO, [$module->id]);
|
||||
static::logFlush();
|
||||
|
||||
$this->assertEvents([
|
||||
[
|
||||
'class' => ModuleEvent::class,
|
||||
'event' => 'afterModuleEnabled',
|
||||
'sender' => $this->moduleManager,
|
||||
'data' => null,
|
||||
'handled' => false,
|
||||
'module' => ['moduleWithMigration' => ModuleWithMigration::class],
|
||||
],
|
||||
]);
|
||||
|
||||
// $module->doDisable = false;
|
||||
// static::assertNull($module->disable());
|
||||
// static::assertNull($module->migrationResult);
|
||||
// static::assertNull($module->migrationOutput);
|
||||
// $this->assertEvents();
|
||||
//
|
||||
// static::assertLog('Module has not been disabled due to beforeDisable() returning false', Logger::LEVEL_WARNING, [$module->id]);
|
||||
// static::logFlush();
|
||||
|
||||
$module->doDisable = true;
|
||||
static::assertTrue($module->disable());
|
||||
// static::assertEquals(ExitCode::OK, $module->migrationResult);
|
||||
// static::assertNotLog('Module has not been enabled due to beforeEnable() returning false', Logger::LEVEL_WARNING, [$module->id]);
|
||||
// static::assertLogRegex('@ > drop table test_module_with_migration \.\.\. done \(time: \d+\.\d+s\)@', Logger::LEVEL_INFO, [$module->id]);
|
||||
static::logFlush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
@ -1014,10 +1087,11 @@ class ModuleManagerTest extends HumHubDbTestCase
|
||||
'module_id' => [
|
||||
'module1',
|
||||
'module2',
|
||||
'moduleWithMigration',
|
||||
'coreModule',
|
||||
'installerModule',
|
||||
'invalidModule1',
|
||||
'invalidModule2'
|
||||
'invalidModule2',
|
||||
]
|
||||
]);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user