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

@@ -7,6 +7,7 @@ use MintyPHP\App\Container\ContainerRegistrar;
use MintyPHP\Module\AddressBook\Service\AddressBookService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\CustomField\CustomFieldRepositoryFactory;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Tenant\TenantScopeService;
@@ -31,7 +32,8 @@ final class AddressBookContainerRegistrar implements ContainerRegistrar
$c->get(TenantScopeService::class),
$c->get(UserCustomFieldValueService::class),
$c->get(UserAvatarService::class),
$c->get(UserProfileViewService::class)
$c->get(UserProfileViewService::class),
$c->get(CustomFieldRepositoryFactory::class)->createTenantCustomFieldOptionRepository()
));
}
}

View File

@@ -2,7 +2,7 @@
namespace MintyPHP\Module\AddressBook\Service;
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepository;
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepositoryInterface;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Org\DepartmentService;
@@ -22,7 +22,8 @@ class AddressBookService
private readonly TenantScopeService $scopeGateway,
private readonly UserCustomFieldValueService $customFieldValueService,
private readonly UserAvatarService $avatarService,
private readonly UserProfileViewService $userProfileViewService
private readonly UserProfileViewService $userProfileViewService,
private readonly TenantCustomFieldOptionRepositoryInterface $tenantCustomFieldOptionRepository
) {
}
@@ -76,7 +77,7 @@ class AddressBookService
}
$customFieldDefinitionIds = array_values(array_unique($customFieldDefinitionIds));
$customFieldOptions = TenantCustomFieldOptionRepository::listByDefinitionIds(
$customFieldOptions = $this->tenantCustomFieldOptionRepository->listByDefinitionIds(
$customFieldDefinitionIds,
true
);

View File

@@ -3,6 +3,7 @@
namespace MintyPHP\Tests\Module\AddressBook\Service;
use MintyPHP\Module\AddressBook\Service\AddressBookService;
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepositoryInterface;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Org\DepartmentService;
@@ -25,6 +26,7 @@ class AddressBookServiceTest extends TestCase
$customFieldGateway = $this->createMock(UserCustomFieldValueService::class);
$avatarService = $this->createMock(UserAvatarService::class);
$userProfileViewService = $this->createMock(UserProfileViewService::class);
$tenantCustomFieldOptionRepository = $this->createMock(TenantCustomFieldOptionRepositoryInterface::class);
$scopeGateway
->expects($this->once())
@@ -73,7 +75,8 @@ class AddressBookServiceTest extends TestCase
$scopeGateway,
$customFieldGateway,
$avatarService,
$userProfileViewService
$userProfileViewService,
$tenantCustomFieldOptionRepository
);
$context = $service->buildIndexContext(7, []);