Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
SystemSettingsService
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 7
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAll
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getByKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 getLogLevelThreshold
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 updateLogLevelThreshold
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 validateSetting
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3declare(strict_types=1);
4
5namespace App\Domain\SystemSettings\Service;
6
7use App\Domain\ErrorLog\Service\ErrorLogService;
8use App\Domain\Exception\BadRequestException;
9use App\Domain\Exception\NotFoundException;
10use App\Domain\Exception\ValidationException;
11use App\Domain\SystemSettings\Data\SystemSettingData;
12use App\Domain\SystemSettings\Repository\SystemSettingsRepository;
13use App\Support\Row;
14use RuntimeException;
15
16/**
17 * Service for system settings business logic.
18 */
19final class SystemSettingsService
20{
21    public function __construct(
22        private readonly SystemSettingsRepository $repository,
23    ) {}
24
25    /**
26     * @return SystemSettingData[]
27     */
28    public function getAll(): array
29    {
30        return $this->repository->findAll();
31    }
32
33    public function getByKey(string $key): ?SystemSettingData
34    {
35        return $this->repository->findByKey($key);
36    }
37
38    /**
39     * @param array<mixed> $value
40     * @param string $key
41     * @param int $updatedBy
42     */
43    public function update(string $key, array $value, int $updatedBy): SystemSettingData
44    {
45        if ($this->repository->findByKey($key) === null) {
46            throw new NotFoundException("Setting '{$key}' not found");
47        }
48
49        $this->validateSetting($key, $value);
50
51        if (!$this->repository->update($key, $value, $updatedBy)) {
52            throw new RuntimeException("Failed to update setting '{$key}'");
53        }
54
55        $updated = $this->repository->findByKey($key);
56
57        if ($updated === null) {
58            throw new RuntimeException("Failed to retrieve setting '{$key}' after update");
59        }
60
61        return $updated;
62    }
63
64    /**
65     * @return array{value: int, level: string}
66     */
67    public function getLogLevelThreshold(): array
68    {
69        return $this->repository->getLogLevelThreshold();
70    }
71
72    public function updateLogLevelThreshold(string $level, int $updatedBy): SystemSettingData
73    {
74        $levels = ErrorLogService::LOG_LEVELS;
75
76        if (!isset($levels[$level])) {
77            throw new ValidationException(
78                "Invalid log level '{$level}'. Valid levels: " . implode(', ', array_keys($levels)),
79            );
80        }
81
82        return $this->update('log_level_threshold', [
83            'value' => $levels[$level],
84            'level' => $level,
85        ], $updatedBy);
86    }
87
88    /**
89     * @param array<mixed> $value
90     * @param string $key
91     */
92    private function validateSetting(string $key, array $value): void
93    {
94        switch ($key) {
95            case 'log_level_threshold':
96                if (!isset($value['value']) || !isset($value['level'])) {
97                    throw new BadRequestException(
98                        "log_level_threshold must have 'value' and 'level' properties",
99                    );
100                }
101
102                $level = Row::string($value, 'level');
103                $valueInt = Row::int($value, 'value');
104                $levels = ErrorLogService::LOG_LEVELS;
105                if (!isset($levels[$level])) {
106                    throw new ValidationException(
107                        'Invalid log level. Valid levels: ' . implode(', ', array_keys($levels)),
108                    );
109                }
110
111                if ($valueInt !== $levels[$level]) {
112                    throw new ValidationException(
113                        "Level value mismatch. '{$level}' should have value {$levels[$level]}",
114                    );
115                }
116                break;
117
118            case 'error_log_retention_days':
119                if (!isset($value['value'])) {
120                    throw new BadRequestException(
121                        "error_log_retention_days must have a 'value' property",
122                    );
123                }
124
125                if (Row::int($value, 'value') < 0) {
126                    throw new ValidationException(
127                        'Retention days must be 0 or greater (0 = indefinite)',
128                    );
129                }
130                break;
131        }
132    }
133}