Responsible for discovering modules from the modules/ Composer project, building ModuleManifest and ModuleRegistrar instances from package metadata and reflection, and generating a cache file that the module registry loads from at runtime.
Discovery
Module discovery is triggered when a module is installed, removed, or updated. Using Composer as a library, the process reads the modules/composer.json and its lock file to enumerate all required packages. For each package, extra.tgp is read alongside the standard composer.json metadata to build the full picture of the module.
The provide block in modules/composer.json is regenerated from the panel's own lock file as part of this process to keep the two in sync.
ModuleManifest
ModuleManifest is a final readonly DTO built from a Composer package. It contains:
ident — derived from the package name (the part after the vendor slug)
vendor — the vendor slug from the package name
version — the package version
name — from extra.tgp
description, license, keywords, authors, support — from CompletePackageInterface where available
definition and icon — from extra.tgp
capabilities — from extra.tgp, mapped to Capability enum cases
core — whether the module is a core module, not installable, updatable, or removable via the module system
registrar — the registrar class string, from extra.tgp
ModuleRegistrar
ModuleRegistrar is a final readonly metadata class built via reflection on the registrar class declared in the manifest. It records:
- The registrar class string
- The register method name, identified by the
#[Register] attribute
- The boot method name, identified by the
#[Boot] attribute
- Collector method mappings, identified by the
#[Collect] attribute — broken into scoped and unscoped variants, and further indexed by PanelContext where provided
- No-context collector mappings for collectors that do not target a specific
PanelContext
Cache File
After discovery and reflection, a cache file is generated containing:
- A map of
ident -> ModuleManifest for all discovered modules
- A list of enabled module idents
- A list of disabled module idents
- A map of
ident -> ModuleRegistrar for enabled modules only
The cache format is a PHP file using new expressions or a similar approach that avoids var_export complexity given the readonly classes involved. The file is regenerated in full on every discovery run.
DI Integration
#[Manifest('ident')] resolvable attribute and resolver — injects a ModuleManifest for the given ident
#[Registrar('ident')] resolvable attribute and resolver — injects a ModuleRegistrar for the given ident
Tasks
Responsible for discovering modules from the
modules/Composer project, buildingModuleManifestandModuleRegistrarinstances from package metadata and reflection, and generating a cache file that the module registry loads from at runtime.Discovery
Module discovery is triggered when a module is installed, removed, or updated. Using Composer as a library, the process reads the
modules/composer.jsonand its lock file to enumerate all required packages. For each package,extra.tgpis read alongside the standardcomposer.jsonmetadata to build the full picture of the module.The
provideblock inmodules/composer.jsonis regenerated from the panel's own lock file as part of this process to keep the two in sync.ModuleManifest
ModuleManifestis afinal readonlyDTO built from a Composer package. It contains:ident— derived from the package name (the part after the vendor slug)vendor— the vendor slug from the package nameversion— the package versionname— fromextra.tgpdescription,license,keywords,authors,support— fromCompletePackageInterfacewhere availabledefinitionandicon— fromextra.tgpcapabilities— fromextra.tgp, mapped toCapabilityenum casescore— whether the module is a core module, not installable, updatable, or removable via the module systemregistrar— the registrar class string, fromextra.tgpModuleRegistrar
ModuleRegistraris afinal readonlymetadata class built via reflection on the registrar class declared in the manifest. It records:#[Register]attribute#[Boot]attribute#[Collect]attribute — broken into scoped and unscoped variants, and further indexed byPanelContextwhere providedPanelContextCache File
After discovery and reflection, a cache file is generated containing:
ident -> ModuleManifestfor all discovered modulesident -> ModuleRegistrarfor enabled modules onlyThe cache format is a PHP file using
newexpressions or a similar approach that avoidsvar_exportcomplexity given the readonly classes involved. The file is regenerated in full on every discovery run.DI Integration
#[Manifest('ident')]resolvable attribute and resolver — injects aModuleManifestfor the given ident#[Registrar('ident')]resolvable attribute and resolver — injects aModuleRegistrarfor the given identTasks
Capabilityenum with all capability casesModuleManifestfinal readonly DTOModuleManifestBuilderto construct aModuleManifestfrom a Composer packageModuleRegistrarfinal readonly metadata classModuleRegistrarBuilderto construct aModuleRegistrarfrom a registrar class#[Register],#[Boot],#[Collect], and#[Unscoped]registrar attributesprovideblock regeneration from the panel lock file#[Manifest]resolvable attribute and resolver#[Registrar]resolvable attribute and resolverModuleManifestBuilderfrom a mock packageModuleRegistrarBuilderreflection output#[Manifest]and#[Registrar]resolution