*/ protected array $subModules = []; protected bool $standalone = false; protected string $component = '@typo3/backend/module/iframe'; protected string $navigationComponent = ''; protected array $defaultModuleData = []; protected array $aliases = []; protected bool $inheritNavigationComponent = true; protected array $routeOptions = []; protected bool $showSubmoduleOverview = false; final protected function __construct(string $identifier) { $this->identifier = $identifier; } public function getIdentifier(): string { return $this->identifier; } public function getPath(): string { return $this->path; } public function getIconIdentifier(): string { if ($this->iconIdentifier === '' && $this->hasParentModule()) { return $this->getParentModule()->getIconIdentifier(); } return $this->iconIdentifier; } public function getTitle(): string { return $this->title; } public function getDescription(): string { return $this->description; } public function getShortDescription(): string { return $this->shortDescription; } public function isStandalone(): bool { return $this->standalone; } public function getNavigationComponent(): string { if ($this->inheritNavigationComponent && $this->hasParentModule()) { // Use parent navigation component if inheritance is enabled. // Fallback if parent does not define a navigation component. return $this->getParentModule()->getNavigationComponent() ?: $this->navigationComponent; } return $this->navigationComponent; } public function getComponent(): string { return $this->component; } public function getPosition(): array { return $this->position; } public function getAccess(): string { return $this->access; } public function getWorkspaceAccess(): string { return $this->workspaceAccess; } public function getParentIdentifier(): string { return $this->parent; } public function setParentModule(ModuleInterface $module): void { $this->parentModule = $module; } public function getParentModule(): ?ModuleInterface { return $this->parentModule; } public function hasParentModule(): bool { return $this->parentModule !== null; } public function addSubModule(ModuleInterface $module): void { $this->subModules[$module->getIdentifier()] = $module; } public function hasSubModule(string $identifier): bool { return isset($this->subModules[$identifier]); } public function hasSubModules(): bool { return $this->subModules !== []; } public function getSubModule(string $identifier): ?ModuleInterface { return $this->subModules[$identifier] ?? null; } public function removeSubModule(string $identifier): void { unset($this->subModules[$identifier]); } /** * @return array */ public function getSubModules(): array { return $this->subModules; } public function getAppearance(): array { return $this->appearance; } public function getAliases(): array { return $this->aliases; } public function hasSubmoduleOverview(): bool { return $this->showSubmoduleOverview; } abstract public function getDefaultRouteOptions(): array; public function getDefaultModuleData(): array { return $this->defaultModuleData; } /** * Promotes this module to a standalone top-level module, inheriting properties from its parent. * * @internal Only to be used by ModuleRegistry */ public function promoteToStandalone(string $navigationComponent, array $position, array $additionalAliases): void { $this->standalone = true; $this->parent = ''; $this->parentModule = null; if ($this->getNavigationComponent() === '') { $this->navigationComponent = $navigationComponent; } if ($this->position === []) { $this->position = $position; } $this->aliases = array_merge($this->aliases, $additionalAliases); } public static function createFromConfiguration(string $identifier, array $configuration): static { $obj = new static($identifier); $obj->packageName = (string)($configuration['packageName'] ?? ''); $obj->absolutePackagePath = (string)($configuration['absolutePackagePath'] ?? ''); $obj->path = '/' . ltrim((string)$configuration['path'], '/'); $obj->standalone = (bool)($configuration['standalone'] ?? false); if ($configuration['parent'] ?? false) { $obj->parent = (string)$configuration['parent']; } if ($configuration['iconIdentifier'] ?? false) { $obj->iconIdentifier = (string)$configuration['iconIdentifier']; } if ($configuration['access'] ?? false) { $obj->access = (string)$configuration['access']; } if ($configuration['workspaces'] ?? false) { $obj->workspaceAccess = (string)$configuration['workspaces']; } if ($configuration['component'] ?? false) { $obj->component = (string)$configuration['component']; } $labelInformation = $configuration['labels'] ?? false; if (is_array($labelInformation)) { $obj->title = (string)($labelInformation['title'] ?? ''); $obj->description = (string)($labelInformation['description'] ?? ''); $obj->shortDescription = (string)($labelInformation['shortDescription'] ?? ''); } elseif (str_starts_with((string)$labelInformation, 'LLL:')) { $labelsFile = $labelInformation; $obj->title = $labelsFile . ':mlang_tabs_tab'; $obj->description = $labelsFile . ':mlang_labels_tabdescr'; $obj->shortDescription = $labelsFile . ':mlang_labels_tablabel'; } elseif (is_string($labelInformation) && !str_contains($labelInformation, ':') && str_contains($labelInformation, '.')) { // New File Format. Uses "backend.modules." (for example "backend.modules.preview") as identifier, // which results in "backend.modules.preview:title" etc. $obj->title = $labelInformation . ':title'; $obj->description = $labelInformation . ':description'; $obj->shortDescription = $labelInformation . ':short_description'; } if (is_array($configuration['position'] ?? false)) { if (in_array('top', $configuration['position'], true)) { $configuration['position'] = [ 'before' => '*', ]; } if (in_array('bottom', $configuration['position'], true)) { $configuration['position'] = [ 'after' => '*', ]; } $obj->position = $configuration['position']; } if (is_array($configuration['appearance'] ?? false)) { $obj->appearance = $configuration['appearance']; } if (is_array($configuration['moduleData'] ?? false)) { $obj->defaultModuleData = $configuration['moduleData']; } if (is_array($configuration['aliases'] ?? false)) { $obj->aliases = $configuration['aliases']; } if (isset($configuration['inheritNavigationComponentFromMainModule'])) { $obj->inheritNavigationComponent = (bool)$configuration['inheritNavigationComponentFromMainModule']; } if (isset($configuration['navigationComponent'])) { $obj->navigationComponent = (string)$configuration['navigationComponent']; } elseif (isset($configuration['navigationComponentId'])) { $obj->navigationComponent = (string)$configuration['navigationComponentId']; } if (is_array($configuration['routeOptions'] ?? null)) { $obj->routeOptions = $configuration['routeOptions']; } if (isset($configuration['showSubmoduleOverview'])) { $obj->showSubmoduleOverview = (bool)$configuration['showSubmoduleOverview']; } return $obj; } }