# Dependency Injection Container Letzte Aktualisierung: 2026-03-06 ## Was ist das und wozu brauchen wir es? Statt dass jede Action-Datei ihre Services selbst zusammenbaut (`new UserAccountService(new UserRepo(), new AuditRepo(), ...)`), gibt es einen zentralen "Service-Speicher": den **AppContainer**. Der Container weiß, wie er jeden Service bauen muss — aber er baut ihn erst, wenn er zum ersten Mal gebraucht wird (lazy). Wird der gleiche Service in derselben Anfrage nochmal angefragt, bekommt man dieselbe Instanz zurück (Singleton pro Request). ## Services abrufen — der `app()` Helper In jeder Action-Datei (`pages/**/*.php`) steht der Container über die globale Hilfsfunktion `app()` zur Verfügung: ```php $userService = app(\MintyPHP\Service\User\UserAccountService::class); $authService = app(\MintyPHP\Service\Access\AuthorizationService::class); ``` Den vollständigen Klassennamen (FQN) als Schlüssel verwenden — so gibt es keine Namenskollisionen und IDEs können Autocomplete nutzen. `app()` wirft eine `RuntimeException` wenn der Service nicht registriert ist. Das ist absichtlich laut, damit fehlende Registrierungen sofort auffallen. ## Aufbau: Registrars Beim Start der Anwendung läuft `core/App/registerContainer.php`. Es erstellt den Container und ruft 8 **Registrars** nacheinander auf: | Registrar | Was er registriert | |---|---| | `RepositoryFactoryRegistrar` | Alle Repository-Factories (SQL-Schicht) | | `ServiceFactoryRegistrar` | Alle Service-Factories (Business-Logik, mit Abhängigkeiten) | | `AccessRegistrar` | RBAC-spezifische Services (Roles, Permissions, Gateways) | | `AuthRegistrar` | Auth-spezifische Services (Login, SSO, API-Tokens) | | `DirectoryRegistrar` | LDAP/Entra-Directory-Services | | `UserRegistrar` | User-spezifische Services und Gateways | | `SettingsRegistrar` | Settings-Services und Gateways | | `AppServicesRegistrar` | Konkrete Top-Level-Services, die direkt in Actions genutzt werden | Jeder Registrar implementiert das Interface `ContainerRegistrar::register(AppContainer $container)`. ## Wie Abhängigkeiten aufgelöst werden ```php // In ServiceFactoryRegistrar: $container->set(UserServicesFactory::class, static fn (AppContainer $c) => new UserServicesFactory( $c->get(AuthServicesFactory::class), // wird lazy aufgelöst $c->get(UserRepositoryFactory::class), $c->get(UserGatewayFactory::class), $c->get(DatabaseSessionRepository::class) ) ); ``` Der Container übergibt sich selbst als `$c` an die Factory-Funktion — so werden alle Abhängigkeiten automatisch und lazy aus dem Container gezogen. Zirkuläre Abhängigkeiten werden über `static fn (): Foo => $c->get(Foo::class)` aufgelöst (der Aufruf wird verzögert, bis er wirklich gebraucht wird). ## Neuen Service registrieren **1. Service und ggf. Factory erstellen** (wie bisher in `core/Service/`) **2. Im passenden Registrar eintragen:** ```php // In AppServicesRegistrar (für Services, die direkt in Actions genutzt werden): $container->set(MeinNeuerService::class, static fn (AppContainer $c) => new MeinNeuerService( $c->get(UserServicesFactory::class), $c->get(SettingGateway::class) ) ); ``` **3. In der Action nutzen:** ```php $meinService = app(\MintyPHP\Service\MeinNeuerService::class); ``` **Faustregel: welcher Registrar?** - Neue *Repository-Factory* → `RepositoryFactoryRegistrar` - Neue *Service-Factory* (mit Abhängigkeiten) → `ServiceFactoryRegistrar` - Konkreter *Service*, der direkt in Actions per `app()` abgerufen wird → `AppServicesRegistrar` - Klar einer Domain zugeordnet (Auth, Access, Directory, User, Settings) → der passende Domain-Registrar ## Wichtige Regeln - **Nie** `new SomeService(...)` direkt in Action-Dateien schreiben — immer `app(SomeService::class)` nutzen. - **Nie** Factory-Ketten in Actions (`app(SomeFactory::class)->createService()`) — den konkreten Service direkt registrieren und per `app()` holen. - Der Container lebt **pro HTTP-Anfrage** — er wird in `web/index.php` initialisiert und über `setAppContainer()` im globalen State abgelegt. - In CLI-Commands wird der Container separat initialisiert (ueber die Runtime-Bootstrap-Klassen unter `core/Console/Support/`). - In `core/Service/**` außerhalb von `*Factory.php` niemals `new ...Factory()`, `new ...Service()` oder `new ...Repository()` direkt instanziieren.