refactor(customfield): interface-based DI for repositories

Align CustomField-Schicht mit core/Repository/Access-Muster. Vier
Repositories (Tenant-Definition, Tenant-Option, User-Value, User-Value-Option)
bekommen je ein Interface, werden von static auf instance umgestellt und
ueber CustomFieldRepositoryFactory injiziert.

TenantCustomFieldService und UserCustomFieldValueService injizieren die
Repository-Interfaces statt statisch aufzurufen. CustomFieldServicesFactory
reicht Instanzen durch. AddressBookService (Modul) bekommt
TenantCustomFieldOptionRepositoryInterface per Container — Interface-Kopplung
verbessert Modul-Isolation gegenueber dem vorherigen statischen Aufruf.

Kein Verhaltenswechsel, keine SQL-Aenderung, keine Service-Signatur-Aenderung.
Alle tenant_id-Parameter erhalten (GR-SEC-009, Security-Review SR-002).

Oeffnet den Weg fuer Cluster B1 (TenantCustomFieldService-Tests) und B2
(UserCustomFieldValueService-Tests), die nun mit createMock() moeglich sind.

Nebenbei zwei PHPStan-Folge-Findings korrigiert:
- Veralteter Ignore-Eintrag fuer findById aus phpstan-baseline.neon entfernt
- Redundanter is_array-Check in TenantCustomFieldOptionRepository entfernt
  (durch typisierte Interface-Signatur abgedeckt)

Gates: QG-001 (1945 Tests, 28581 Assertions) / QG-002 / QG-003 / QG-006 pass.

Workflow: .agents/runs/CUSTOMFIELD-DI-REFACTOR-001/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 19:32:14 +02:00
parent 0da785f4b7
commit 6b05bbfe9c
18 changed files with 227 additions and 83 deletions

View File

@@ -9,6 +9,7 @@ use MintyPHP\Repository\Stats\AdminStatsRepository;
use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Service\Access\AccessRepositoryFactory;
use MintyPHP\Service\Auth\AuthRepositoryFactory;
use MintyPHP\Service\CustomField\CustomFieldRepositoryFactory;
use MintyPHP\Service\Directory\DirectoryRepositoryFactory;
use MintyPHP\Service\Import\ImportRepositoryFactory;
use MintyPHP\Service\Mail\MailRepositoryFactory;
@@ -32,6 +33,7 @@ final class RepositoryFactoryRegistrar implements ContainerRegistrar
$container->set(AccessRepositoryFactory::class, static fn (): AccessRepositoryFactory => new AccessRepositoryFactory());
$container->set(UserRepositoryFactory::class, static fn (): UserRepositoryFactory => new UserRepositoryFactory());
$container->set(AuthRepositoryFactory::class, static fn (): AuthRepositoryFactory => new AuthRepositoryFactory());
$container->set(CustomFieldRepositoryFactory::class, static fn (): CustomFieldRepositoryFactory => new CustomFieldRepositoryFactory());
// These repositories have no factory because they're standalone — no shared config or gateway needed.
$container->set(AdminStatsRepository::class, static fn (): AdminStatsRepository => new AdminStatsRepository());
$container->set(SearchQueryRepository::class, static fn (): SearchQueryRepository => new SearchQueryRepository());

View File

@@ -25,6 +25,7 @@ use MintyPHP\Service\Auth\AuthGatewayFactory;
use MintyPHP\Service\Auth\AuthRepositoryFactory;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\Branding\BrandingServicesFactory;
use MintyPHP\Service\CustomField\CustomFieldRepositoryFactory;
use MintyPHP\Service\CustomField\CustomFieldServicesFactory;
use MintyPHP\Service\Directory\DirectoryGatewayFactory;
use MintyPHP\Service\Directory\DirectoryRepositoryFactory;
@@ -67,7 +68,8 @@ final class ServiceFactoryRegistrar implements ContainerRegistrar
));
$container->set(CustomFieldServicesFactory::class, static fn (AppContainer $c): CustomFieldServicesFactory => new CustomFieldServicesFactory(
$c->get(TenantRepository::class),
$c->get(TenantScopeService::class)
$c->get(TenantScopeService::class),
$c->get(CustomFieldRepositoryFactory::class)
));
$container->set(TenantServicesFactory::class, static fn (AppContainer $c): TenantServicesFactory => new TenantServicesFactory(
$c->get(PermissionService::class),