Merge pull request #3234 from danielkesselberg/feature/improve-moduleloader

Improve moduleloader
This commit is contained in:
Daniel Kesselberg 2018-09-21 21:13:35 +02:00 committed by GitHub
commit f8a3b14c9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 176 additions and 5 deletions

View File

@ -19,7 +19,7 @@ class Yii extends \yii\BaseYii
* Used for properties that are identical for both WebApplication and ConsoleApplication
* @property-read \humhub\components\ModuleManager $moduleManager
* @property-read \humhub\components\i18n\I18N $i18n
* @property-read \humhub\components\mail\Mailer $mailer
* @property-read \humhub\components\mail\Mailer $mailer
* @property-read \humhub\modules\ui\view\components\View $view
* @property-read \humhub\components\SettingsManager $settings
* @property-read \humhub\modules\notification\components\NotificationManager $notification

View File

@ -1,5 +1,4 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
@ -8,8 +7,10 @@
namespace humhub\components\bootstrap;
use humhub\components\Application;
use Yii;
use yii\base\BootstrapInterface;
use yii\helpers\FileHelper;
/**
* ModuleAutoLoader automatically searches for config.php files in module folder an executes them.
@ -19,8 +20,26 @@ use yii\base\BootstrapInterface;
class ModuleAutoLoader implements BootstrapInterface
{
const CACHE_ID = 'module_configs';
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
*/
public function bootstrap($app)
{
$modules = self::locateModules();
Yii::$app->moduleManager->registerBulk($modules);
}
/**
* Find available modules
* @deprecated 1.3 replace call for locateModules with findModules and handle caching outside of method (e.g. in boostrap)
* @return array|bool|mixed
*/
public static function locateModules()
{
$modules = Yii::$app->cache->get(self::CACHE_ID);
@ -43,11 +62,52 @@ class ModuleAutoLoader implements BootstrapInterface
}
}
}
if (!YII_DEBUG) {
Yii::$app->cache->set(self::CACHE_ID, $modules);
Yii::$app->cache->set(self::CACHE_ID, $modules);
}
return $modules;
}
/**
* Find all modules with configured paths
* @param array $paths
* @return array
*/
public static function findModules($paths)
{
$folders = [];
foreach ($paths as $path) {
$folders = array_merge($folders, self::findModulesByPath($path));
}
$modules = [];
foreach ($folders as $folder) {
try {
/** @noinspection PhpIncludeInspection */
$modules[$folder] = require $folder . DIRECTORY_SEPARATOR . self::CONFIGURATION_FILE;
} catch (\Exception $e) {
Yii::error($e);
}
}
Yii::$app->moduleManager->registerBulk($modules);
return $modules;
}
/**
* Find all directories with a configuration file inside
* @param string $path
* @return array
*/
public static function findModulesByPath($path)
{
$hasConfigurationFile = function ($path) {
return is_file($path . DIRECTORY_SEPARATOR . self::CONFIGURATION_FILE);
};
try {
return FileHelper::findDirectories(Yii::getAlias($path, true), ['filter' => $hasConfigurationFile, 'recursive' => false]);
} catch (yii\base\InvalidArgumentException $e) {
return [];
}
}
}

View File

@ -0,0 +1,111 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\tests\codeception\unit;
use Codeception\Test\Unit;
use humhub\components\bootstrap\ModuleAutoLoader;
use Yii;
/**
* Class ModuleAutoLoaderTest
*/
class ModuleAutoLoaderTest extends Unit
{
/** @var array list of expected core modules */
const EXPECTED_CORE_MODULES = [
'activity',
'admin',
'comment',
'content',
'dashboard',
'directory',
'file',
'friendship',
'installer',
'like',
'live',
'notification',
'post',
'queue',
'search',
'space',
'stream',
'topic',
'tour',
'ui',
'user',
];
/**
* @var \UnitTester
*/
protected $tester;
/**
* Assert that locateModules find all core modules
*/
public function testCoreModuleLoading()
{
$modules = array_column(
ModuleAutoLoader::locateModules(),
'id'
);
/* assert that every core module is found by module loader. expected result of array_diff is an empty array. */
$this->assertEmpty(array_diff(self::EXPECTED_CORE_MODULES, $modules), 'expected core modules are not resolved by auto loader.');
}
/**
* Test that an invalid path for module loading leads to an exception
*/
public function testInvalidModulePath()
{
array_push(Yii::$app->params['moduleAutoloadPaths'], '/dev/null');
try {
ModuleAutoLoader::locateModules();
$this->fail('no expection when invalid path for moduleAutoloadPaths');
} catch (\ErrorException $e) {
}
array_pop(Yii::$app->params['moduleAutoloadPaths']);
}
/**
* Test module loading by path
* @dataProvider dataModuleLoadingByPath
*/
public function testModuleLoadingByPath($path, $count)
{
$this->assertCount($count, ModuleAutoLoader::findModulesByPath($path));
}
/**
* Return test cases for module loading by path
* @return array
*/
public function dataModuleLoadingByPath()
{
return [
['@humhub/modules', count(self::EXPECTED_CORE_MODULES)],
['@humhub/invalid', 0],
['@invalid/folder', 0]
];
}
/**
* Assert that locateModules and findModules return the same list of modules
*/
public function testLocateAndFindModules()
{
$this->assertEquals(
ModuleAutoLoader::locateModules(),
ModuleAutoLoader::findModules(Yii::$app->params['moduleAutoloadPaths'])
);
}
}