Files
breadcrumb-the-shire/core/Service/Settings/SettingsAppGateway.php
fs 0e86925464 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>
2026-04-13 23:20:42 +02:00

203 lines
6.3 KiB
PHP

<?php
namespace MintyPHP\Service\Settings;
use MintyPHP\I18n;
class SettingsAppGateway
{
public function __construct(
private readonly SettingsMetadataGateway $settingsMetadataGateway,
private readonly ThemeConfigGateway $themeConfigService
) {
}
public function getAppTitle(): ?string
{
$value = $this->settingsMetadataGateway->getValue(SettingKeys::APP_TITLE_KEY);
$value = $value !== null ? trim($value) : null;
return $value !== '' ? $value : null;
}
public function setAppTitle(?string $title, ?string $description = null): bool
{
$value = $title !== null ? trim($title) : null;
if ($value === '') {
$value = null;
}
$desc = $description ?? 'setting.app_title';
return $this->settingsMetadataGateway->set(SettingKeys::APP_TITLE_KEY, $value, $desc);
}
public function getAppLocale(): ?string
{
$value = $this->settingsMetadataGateway->getValue(SettingKeys::APP_LOCALE_KEY);
$value = $value !== null ? trim($value) : '';
return $value !== '' ? $value : null;
}
public function setAppLocale(?string $locale, ?string $description = null): bool
{
$value = $locale !== null ? trim($locale) : '';
if ($value === '') {
$value = null;
} else {
$allowed = defined('APP_LOCALES') ? APP_LOCALES : [];
if ($allowed && !in_array($value, $allowed, true)) {
return false;
}
}
$desc = $description ?? 'setting.app_locale';
return $this->settingsMetadataGateway->set(SettingKeys::APP_LOCALE_KEY, $value, $desc);
}
public function getAppTheme(): ?string
{
$value = $this->settingsMetadataGateway->getValue(SettingKeys::APP_THEME_KEY);
$value = $value !== null ? strtolower(trim($value)) : '';
if (!$this->isAllowedTheme($value)) {
return null;
}
return $value;
}
public function setAppTheme(?string $theme, ?string $description = null): bool
{
$value = $theme !== null ? strtolower(trim($theme)) : '';
if ($value === '' || !$this->isAllowedTheme($value)) {
$value = null;
}
$desc = $description ?? 'setting.app_theme';
return $this->settingsMetadataGateway->set(SettingKeys::APP_THEME_KEY, $value, $desc);
}
/**
* @return array<string, string>
*/
public function listThemes(): array
{
return $this->themeConfigService->all();
}
public function isAllowedTheme(?string $theme): bool
{
$value = strtolower(trim((string) $theme));
return $value !== '' && in_array($value, $this->allowedThemes(), true);
}
public function resolveDefaultTheme(): string
{
$settingTheme = $this->getAppTheme();
if ($settingTheme !== null) {
return $settingTheme;
}
$envTheme = strtolower(trim((string) (getenv('APP_THEME') ?: '')));
if ($this->isAllowedTheme($envTheme)) {
return $envTheme;
}
$allowedThemes = $this->allowedThemes();
if (in_array('light', $allowedThemes, true)) {
return 'light';
}
return (string) ($allowedThemes[0] ?? 'light');
}
public function normalizeTheme(?string $theme): string
{
$value = strtolower(trim((string) $theme));
if ($this->isAllowedTheme($value)) {
return $value;
}
return $this->resolveDefaultTheme();
}
public function isUserThemeAllowed(): bool
{
return settingToBool(
$this->settingsMetadataGateway->getValue(SettingKeys::APP_THEME_USER_KEY),
true
);
}
public function setUserThemeAllowed(bool $allowed, ?string $description = null): bool
{
$value = $allowed ? '1' : '0';
$desc = $description ?? 'setting.app_theme_user';
return $this->settingsMetadataGateway->set(SettingKeys::APP_THEME_USER_KEY, $value, $desc);
}
public function isRegistrationEnabled(): bool
{
return settingToBool(
$this->settingsMetadataGateway->getValue(SettingKeys::APP_REGISTRATION_KEY),
true
);
}
public function setRegistrationEnabled(bool $allowed, ?string $description = null): bool
{
$value = $allowed ? '1' : '0';
$desc = $description ?? 'setting.app_registration';
return $this->settingsMetadataGateway->set(SettingKeys::APP_REGISTRATION_KEY, $value, $desc);
}
public function getAppPrimaryColor(): ?string
{
$value = $this->settingsMetadataGateway->getValue(SettingKeys::APP_PRIMARY_COLOR_KEY);
$value = $value !== null ? strtolower(trim($value)) : '';
if ($value === '') {
return null;
}
if (!preg_match('/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i', $value)) {
return null;
}
return $value;
}
public function setAppPrimaryColor(?string $color, ?string $description = null): bool
{
$value = $color !== null ? strtolower(trim($color)) : '';
if ($value !== '' && $value[0] !== '#') {
if (preg_match('/^[0-9a-f]{3}$/i', $value)
|| preg_match('/^[0-9a-f]{4}$/i', $value)
|| preg_match('/^[0-9a-f]{6}$/i', $value)
|| preg_match('/^[0-9a-f]{8}$/i', $value)) {
$value = '#' . $value;
}
}
if ($value === '') {
$value = null;
} elseif (!preg_match('/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i', $value)) {
return false;
}
$desc = $description ?? 'setting.app_primary_color';
return $this->settingsMetadataGateway->set(SettingKeys::APP_PRIMARY_COLOR_KEY, $value, $desc);
}
private function allowedThemes(): array
{
return array_keys($this->listThemes());
}
public function normalizeLocale(?string $locale): string
{
$value = strtolower(trim((string) $locale));
$available = defined('APP_LOCALES') ? APP_LOCALES : [I18n::$defaultLocale];
if ($value === '' || !in_array($value, $available, true)) {
return I18n::$locale ?? I18n::$defaultLocale;
}
return $value;
}
}