refactor: rename lib/ to core/ for clearer core-module separation
Rename the top-level lib/ directory to core/ so the project root immediately communicates which code is core platform and which lives in modules/. PHP namespaces (MintyPHP\*) are unchanged — only the Composer PSR-4 path mapping moves from lib/ to core/. Module-internal lib/ directories (modules/*/lib/) are untouched. Updated across the full stack: - composer.json PSR-4 mapping - bootstrap entry points (web/index.php, bin/*, tests/bootstrap.php) - tooling configs (phpstan.neon, phpunit.xml, php-cs-fixer) - 26 architecture contract tests - enforcement-policy, guard-catalog, quality-gates - all documentation (CLAUDE.md, README, 25 docs/, .agents/skills/) - bin/qa-extended.sh search paths - .claude/settings.local.json permission paths Workflow: .agents/runs/CORE-LIB-RENAME-001/ (Analyst → Planner → Executor → Code Review (4 findings fixed) → Security Review → Acceptance Test → Finalizer) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
106
core/Service/User/UserAccessTemplateService.php
Normal file
106
core/Service/User/UserAccessTemplateService.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\User;
|
||||
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\I18n;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepository;
|
||||
use MintyPHP\Service\Auth\TenantSsoService;
|
||||
|
||||
class UserAccessTemplateService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TenantSsoService $tenantSsoService,
|
||||
private readonly UserDirectoryGateway $userDirectoryGateway,
|
||||
private readonly UserTenantRepository $userTenantRepository
|
||||
) {
|
||||
}
|
||||
|
||||
// Builds locale-aware template variables shared by mail and PDF onboarding output.
|
||||
public function buildContext(array $user): array
|
||||
{
|
||||
$locale = $this->resolveLocale($user);
|
||||
$name = trim((string) (($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? '')));
|
||||
$isGerman = str_starts_with($locale, 'de');
|
||||
$greeting = $isGerman ? 'Hallo' : 'Hello';
|
||||
if ($name !== '') {
|
||||
$greeting .= ' ' . $name;
|
||||
}
|
||||
$greeting .= ',';
|
||||
|
||||
$loginUrl = $this->resolveTenantLoginUrl($user, $locale);
|
||||
$resetUrl = appUrl(Request::withLocale('password/forgot', $locale));
|
||||
|
||||
// Temporarily switch locale so subject translation matches recipient language.
|
||||
$previousLocale = I18n::$locale ?? null;
|
||||
I18n::$locale = $locale;
|
||||
$subject = t('Your access details');
|
||||
I18n::$locale = $previousLocale;
|
||||
|
||||
return [
|
||||
'locale' => $locale,
|
||||
'subject' => $subject,
|
||||
'vars' => [
|
||||
'app_name' => appTitle(),
|
||||
'app_logo_url' => appLogoUrlAbsolute(128),
|
||||
'imprint_url' => appUrl(Request::withLocale('imprint', $locale)),
|
||||
'privacy_url' => appUrl(Request::withLocale('privacy', $locale)),
|
||||
'greeting' => $greeting,
|
||||
'username' => (string) ($user['email'] ?? ''),
|
||||
'login_url' => $loginUrl,
|
||||
'reset_url' => $resetUrl,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function resolveLocale(array $user): string
|
||||
{
|
||||
// Keep user locale within configured APP_LOCALES; otherwise fallback to app default.
|
||||
$locale = strtolower(trim((string) ($user['locale'] ?? '')));
|
||||
if ($locale === '') {
|
||||
$locale = I18n::$locale ?? I18n::$defaultLocale;
|
||||
}
|
||||
$available = defined('APP_LOCALES') && is_array(APP_LOCALES) ? APP_LOCALES : [];
|
||||
if ($available && !in_array($locale, $available, true)) {
|
||||
$locale = I18n::$defaultLocale;
|
||||
}
|
||||
return $locale;
|
||||
}
|
||||
|
||||
private function resolveTenantLoginUrl(array $user, string $locale): string
|
||||
{
|
||||
$tenantIds = [];
|
||||
$primaryTenantId = (int) ($user['primary_tenant_id'] ?? 0);
|
||||
$currentTenantId = (int) ($user['current_tenant_id'] ?? 0);
|
||||
if ($primaryTenantId > 0) {
|
||||
$tenantIds[] = $primaryTenantId;
|
||||
}
|
||||
if ($currentTenantId > 0 && $currentTenantId !== $primaryTenantId) {
|
||||
$tenantIds[] = $currentTenantId;
|
||||
}
|
||||
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
if (!$tenantIds && $userId > 0) {
|
||||
$tenantIds = array_values(array_map(
|
||||
'intval',
|
||||
$this->userTenantRepository->listTenantIdsByUserId($userId)
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($tenantIds as $tenantId) {
|
||||
if ($tenantId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$tenant = $this->userDirectoryGateway->findTenant($tenantId);
|
||||
if (!$tenant || (string) ($tenant['status'] ?? 'active') !== 'active') {
|
||||
continue;
|
||||
}
|
||||
$tenantSlug = $this->tenantSsoService->tenantLoginSlug($tenant);
|
||||
if ($tenantSlug !== '') {
|
||||
return appUrl(Request::withLocale('login?tenant=' . rawurlencode($tenantSlug), $locale));
|
||||
}
|
||||
}
|
||||
|
||||
return appUrl(Request::withLocale('login', $locale));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user