Registry
How modules are auto-discovered and their configs cached for runtime access.
The Registry is Nibiru’s module-config cache. At boot it walks every directory under application/module/, parses each module’s settings/*.ini, and exposes the parsed config through a single accessor. Think of it as the gravitational centre that keeps modules in orbit around each other.
How discovery works
Section titled “How discovery works”For each module under application/module/<name>/settings/:
- The Registry iterates files matching
*.ini. - For each, it tries the environment-specific filename first (
<base>.<env>.<ext>, e.g.users.production.ini); falls back to the base name (users.ini). - It calls
parse_ini_file($path, true)(multi-section). - It looks for a section named after the module, uppercased —
[USERS],[CMS],[ANALYTICS]. - The parsed key/value pairs become an
\stdClasskeyed by the module name.
Reading a module’s config
Section titled “Reading a module’s config”$users = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');$users->session_lifetime;$users->password_min_length;$users->allowed_roles; / arrayInside the module itself the convention is to wrap this in a setter:
class Users extends ModuleAdapter implements IModule{ const CONFIG_MODULE_NAME = 'users'; protected static \stdClass $usersRegistry;
protected function setUsersRegistry(): void { self::$usersRegistry = Registry::getInstance() ->loadModuleConfigByName(self::CONFIG_MODULE_NAME); }
public static function lifetime(): int { return (int) self::$usersRegistry->session_lifetime; }}Why uppercase section names?
Section titled “Why uppercase section names?”INI section names are conventionally uppercased to make them visually distinct. The Registry assumes this, so a module called cms looks for [CMS]. Always uppercase.
Multi-INI per module
Section titled “Multi-INI per module”Nothing stops you from having more than one INI file in a module’s settings/ folder. The Registry parses them all and merges everything matching [<MODULE>] into the same \stdClass. Useful for splitting concerns:
application/module/users/settings/├── users.ini # [USERS] base config├── users.smtp.ini # [USERS] mail-related keys└── users.production.ini # production overrideWhen to use the Registry vs Config
Section titled “When to use the Registry vs Config”Config | Registry | |
|---|---|---|
| Source | settings.<env>.ini (one file) | per-module INIs (many files) |
| Scope | app-wide framework config | module-specific config |
| Sections | mixed (DATABASE, SETTINGS, ENGINE…) | one per module |
| Lookup | Config::getInstance()->getConfig()['DATABASE']['driver'] | Registry::getInstance()->loadModuleConfigByName('users') |
A module that needs to read [DATABASE] driver reaches for Config. A module that needs to read its own [USERS] session_lifetime reaches for Registry.
Listing all loaded modules
Section titled “Listing all loaded modules”$registry = \Nibiru\Registry::getInstance();foreach ($registry->getModuleNames() as $name) { $cfg = $registry->loadModuleConfigByName($name); echo "$name → " . print_r($cfg, true) . "\n";}Useful in a debug controller or admin dashboard.
Reload semantics
Section titled “Reload semantics”Like Config, the Registry is a singleton populated once per request. If you change a module’s INI you need to refresh the request to see the new values. There’s a destroy() method on the Registry singleton if you really need to reload mid-request, but in normal flows you won’t.
Common pitfalls
Section titled “Common pitfalls”- Section name doesn’t match the module folder. Folder
users/, expected section[USERS]. Mismatch → empty config. - INI file extension. Only
*.iniis parsed. A*.confor*.configfile is ignored. - Environment file beats base file silently. If
users.production.iniexists with[USERS]it shadowsusers.inientirely — not merged. Keep both files in sync, or use one + an overlay.