Files

226 lines
6.5 KiB
PHP

<?php
/**
* ============================================================
*
* @project biiproject
*
* @author Andika Debi Putra
*
* @email andikadebiputra@gmail.com
*
* @website https://biiproject.com
*
* @copyright Copyright (c) 2026 Andika Debi Putra
* @license Proprietary - All Rights Reserved
*
* @version 1.0.0
*
* @created 2026-05-01
* ============================================================
*
* Unauthorized copying, modification, distribution, or use
* of this file is strictly prohibited without prior written
* permission from the author.
* ============================================================
*/
namespace App\Services\SystemConfig;
use App\Models\SystemSettingRevision;
use App\Repositories\SystemSettingRepository;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class SystemConfigService
{
private const CACHE_KEY = 'system_settings.all';
private const PUBLIC_CACHE_KEY = 'system_settings.public';
private const CACHE_TTL_MINUTES = 60;
protected static ?array $resolvedSettings = null;
public function __construct(
protected SystemSettingRepository $repository,
protected SettingFileUploader $fileUploader = new SettingFileUploader,
) {}
public static function definitions(): array
{
return SettingDefinitions::ALL;
}
public function all(bool $forceRefresh = false): array
{
if ($forceRefresh) {
$this->invalidateCache();
}
if (self::$resolvedSettings !== null) {
return self::$resolvedSettings;
}
try {
return self::$resolvedSettings = Cache::remember(
self::CACHE_KEY,
now()->addMinutes(self::CACHE_TTL_MINUTES),
fn () => $this->resolveAll(),
);
} catch (\Exception) {
return self::$resolvedSettings = $this->resolveAll();
}
}
public function getPublicSettings(): array
{
try {
return Cache::remember(
self::PUBLIC_CACHE_KEY,
now()->addMinutes(self::CACHE_TTL_MINUTES),
fn () => $this->buildPublicSettings(),
);
} catch (\Exception) {
return $this->buildPublicSettings();
}
}
public function grouped(): array
{
$all = $this->all();
$grouped = [];
foreach (SettingDefinitions::ALL as $key => $meta) {
$grouped[$meta['group']][$key] = $all[$key] ?? $meta['default'] ?? null;
}
return $grouped;
}
public function get(string $key, mixed $default = null): mixed
{
if (! array_key_exists($key, SettingDefinitions::ALL)) {
return $default;
}
return $this->all()[$key] ?? $default;
}
public function update(array $input, array $files = [], ?int $actorId = null, ?Request $request = null): void
{
$current = $this->all();
foreach (SettingDefinitions::ALL as $key => $meta) {
$oldValue = $current[$key] ?? $meta['default'] ?? null;
$newValue = $this->resolveNewValue($key, $meta, $input, $files, $oldValue);
if (SettingValueCaster::isUnchanged($oldValue, $newValue)) {
continue;
}
$setting = $this->repository->upsert([
'key' => $key,
'value' => SettingValueCaster::serialize($newValue),
'type' => $meta['type'],
'group' => $meta['group'],
'is_public' => (bool) $meta['is_public'],
'description' => $meta['description'],
'created_by' => $actorId,
'updated_by' => $actorId,
]);
$this->writeRevision($setting->id, $key, $oldValue, $newValue, $actorId, $request);
}
$this->invalidateCache();
}
protected function resolveNewValue(string $key, array $meta, array $input, array $files, mixed $oldValue): mixed
{
if ($meta['type'] === 'image_path') {
return isset($files[$key])
? $this->fileUploader->replace($key, $files[$key], $oldValue)
: $oldValue;
}
return array_key_exists($key, $input)
? SettingValueCaster::normalize($input[$key], (string) $meta['type'])
: $oldValue;
}
protected function resolveAll(): array
{
try {
if (! $this->repository->tableExists()) {
return $this->definitionDefaults();
}
$rows = $this->repository->all();
} catch (\Exception) {
return $this->definitionDefaults();
}
$resolved = [];
foreach (SettingDefinitions::ALL as $key => $meta) {
$record = $rows->firstWhere('key', $key);
$resolved[$key] = $record
? SettingValueCaster::deserialize($record->value, (string) $record->type)
: ($meta['default'] ?? null);
}
return $resolved;
}
protected function buildPublicSettings(): array
{
$all = $this->all();
$public = [];
foreach (SettingDefinitions::ALL as $key => $meta) {
if (! $meta['is_public']) {
continue;
}
$public[$key] = $all[$key] ?? $meta['default'] ?? null;
}
return $public;
}
protected function definitionDefaults(): array
{
$defaults = [];
foreach (SettingDefinitions::ALL as $key => $meta) {
$defaults[$key] = $meta['default'] ?? null;
}
return $defaults;
}
protected function writeRevision(
int $settingId,
string $key,
mixed $oldValue,
mixed $newValue,
?int $actorId,
?Request $request,
): void {
SystemSettingRevision::query()->create([
'system_setting_id' => $settingId,
'key' => $key,
'old_value' => $oldValue === null ? null : json_encode($oldValue, JSON_UNESCAPED_SLASHES),
'new_value' => $newValue === null ? null : json_encode($newValue, JSON_UNESCAPED_SLASHES),
'changed_by' => $actorId,
'changed_ip' => $request?->ip(),
'changed_agent' => $request?->userAgent(),
'created_at' => now(),
]);
}
protected function invalidateCache(): void
{
Cache::forget(self::CACHE_KEY);
Cache::forget(self::PUBLIC_CACHE_KEY);
self::$resolvedSettings = null;
}
}