diff --git a/app/Module/ModuleContainerInterface.php b/app/Module/ModuleContainerInterface.php new file mode 100644 index 00000000000..1a645e7e91a --- /dev/null +++ b/app/Module/ModuleContainerInterface.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace Fisharebest\Webtrees\Module; + +use Illuminate\Support\Collection; + +/** + * Interface ModuleCustomInterface - Classes and libraries for module system + */ +interface ModuleContainerInterface extends ModuleCustomInterface +{ + /** + * The list of modules contained within this module. + * + * @return Collection + */ + public function containedModules(): Collection; +} diff --git a/app/Module/ModuleContainerTrait.php b/app/Module/ModuleContainerTrait.php new file mode 100644 index 00000000000..931b0eb3536 --- /dev/null +++ b/app/Module/ModuleContainerTrait.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace Fisharebest\Webtrees\Module; + +use Illuminate\Support\Collection; + +/** + * Trait ModuleContainerTrait - default implementation of ModuleCustomInterface + */ +trait ModuleContainerTrait +{ + /** + * The list of modules contained within this module. + * + * @return Collection + */ + public function containedModules(): Collection + { + return new Collection(); + } +} diff --git a/app/Services/ModuleService.php b/app/Services/ModuleService.php index 8fed193019c..cb980fd2fc3 100644 --- a/app/Services/ModuleService.php +++ b/app/Services/ModuleService.php @@ -187,6 +187,7 @@ use Fisharebest\Webtrees\Module\ModuleAnalyticsInterface; use Fisharebest\Webtrees\Module\ModuleBlockInterface; use Fisharebest\Webtrees\Module\ModuleChartInterface; +use Fisharebest\Webtrees\Module\ModuleContainerInterface; use Fisharebest\Webtrees\Module\ModuleCustomInterface; use Fisharebest\Webtrees\Module\ModuleDataFixInterface; use Fisharebest\Webtrees\Module\ModuleFooterInterface; @@ -703,16 +704,30 @@ private function customModules(): Collection return strlen($module_name) <= 30; }) - ->map(static function (string $filename): ?ModuleCustomInterface { + ->flatMap(static function (string $filename): Collection { $module = self::load($filename); if ($module instanceof ModuleCustomInterface) { - $module->setName('_' . basename(dirname($filename)) . '_'); - - return $module; + $moduleName = '_' . basename(dirname($filename)) . '_'; + $module->setName($moduleName); + + if ($module instanceof ModuleContainerInterface) { + $collection = $module->containedModules() + //force numeric keys + ->values(); + + $collection->each(function (ModuleCustomInterface $submodule, int $key) use ($moduleName) { + $submodule->setName($moduleName . $key); + }); + + $collection->prepend($module); + return $collection; + } + + return new Collection([$module]); } - return null; + return new Collection(); }) ->filter() ->mapWithKeys(static function (ModuleCustomInterface $module): array {