asdasd
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-29 02:32:42 +02:00
parent 4ead35047a
commit 79872f3337
5 changed files with 159 additions and 191 deletions

View File

@@ -19,17 +19,17 @@ final class FxRatesService
public function latestStatus(): ?array
{
return $this->repository->getLatestFetch($this->defaultBaseCurrency());
return $this->localizeFetch($this->repository->getLatestFetch($this->defaultBaseCurrency()));
}
public function latestStatuses(): array
{
return $this->repository->listLatestFetches();
return array_map(fn (array $fetch): array => $this->localizeFetch($fetch), $this->repository->listLatestFetches());
}
public function recentFetches(int $limit = 20): array
{
return $this->repository->listRecentFetches($limit);
return array_map(fn (array $fetch): array => $this->localizeFetch($fetch), $this->repository->listRecentFetches($limit));
}
public function snapshot(?string $baseCurrency = null, ?string $at = null, ?array $symbols = null, ?int $windowMinutes = null): ?array
@@ -53,7 +53,7 @@ final class FxRatesService
return null;
}
return $this->rebaseSnapshot($snapshot, $base, $symbols);
return $this->localizeSnapshot($this->rebaseSnapshot($snapshot, $base, $symbols));
}
$atUtc = $this->normalizeTimestamp($at);
@@ -76,10 +76,10 @@ final class FxRatesService
return null;
}
return $rebased + [
return $this->localizeSnapshot($rebased + [
'requested_at' => $atUtc,
'distance_seconds' => $nearest['distance_seconds'] ?? null,
];
]);
}
public function findRate(?string $fromCurrency, ?string $toCurrency, ?string $at = null, ?int $windowMinutes = null): ?array
@@ -91,7 +91,7 @@ final class FxRatesService
}
if ($from === $to) {
return [
return $this->localizeRateResult([
'base_currency' => $from,
'target_currency' => $to,
'rate' => 1.0,
@@ -99,7 +99,7 @@ final class FxRatesService
'fetched_at' => $at ? $this->normalizeTimestamp($at) : null,
'rate_date' => $at ? substr((string) $this->normalizeTimestamp($at), 0, 10) : gmdate('Y-m-d'),
'is_exact_pair' => true,
];
]);
}
$cacheKey = implode(':', [$from, $to, $at ?? '', (string) ($windowMinutes ?? 0)]);
@@ -124,7 +124,7 @@ final class FxRatesService
$rates = is_array($snapshot['rates'] ?? null) ? $snapshot['rates'] : [];
$resolved = $this->resolveRateFromSnapshot($snapshot, $rates, $from, $to);
if ($resolved !== null) {
return $this->memoryCache[$cacheKey] = $resolved;
return $this->memoryCache[$cacheKey] = $this->localizeRateResult($resolved);
}
}
@@ -148,7 +148,7 @@ final class FxRatesService
public function refreshLatestRates(?array $currencies = null, ?string $baseCurrency = null): array
{
$requestedBase = $this->normalizeCurrency($baseCurrency ?: $this->defaultBaseCurrency());
$payload = $this->fetchLatestPayload($requestedBase, $currencies);
$payload = $this->fetchLatestPayload($requestedBase, null);
$base = $this->normalizeCurrency((string) ($payload['base'] ?? $requestedBase));
if ($base === '') {
$base = $requestedBase !== '' ? $requestedBase : 'USD';
@@ -169,7 +169,7 @@ final class FxRatesService
'rate_date' => $rateDate,
'updated_count' => count($saved['rates'] ?? []),
'rates' => $saved['rates'] ?? [],
'fetch' => $saved['fetch'] ?? null,
'fetch' => $this->localizeFetch(is_array($saved['fetch'] ?? null) ? $saved['fetch'] : null),
];
}
@@ -186,7 +186,7 @@ final class FxRatesService
'rate_date' => $latest['rate_date'] ?? null,
'updated_count' => 0,
'rates' => [],
'fetch' => $latest,
'fetch' => $this->localizeFetch($latest),
'reused' => true,
];
}
@@ -210,7 +210,7 @@ final class FxRatesService
$direct = $this->repository->listDirectHistory($fromCurrency, $toCurrency, $this->normalizeTimestamp($from), $this->normalizeTimestamp($to), $limit);
if ($direct !== []) {
return $direct;
return array_map(fn (array $row): array => $this->localizeRateResult($row), $direct);
}
$inverse = $this->repository->listDirectHistory($toCurrency, $fromCurrency, $this->normalizeTimestamp($from), $this->normalizeTimestamp($to), $limit);
@@ -237,7 +237,7 @@ final class FxRatesService
];
}
return $result;
return array_map(fn (array $row): array => $this->localizeRateResult($row), $result);
}
public function runScheduledRefresh(array $context = []): array
@@ -268,7 +268,7 @@ final class FxRatesService
'ok' => true,
'message' => 'Kein FX-Abruf: fuer heute existiert bereits ein Snapshot nach ' . str_pad((string) $targetHour, 2, '0', STR_PAD_LEFT) . ':00.',
'skipped' => true,
'fetch' => $latest,
'fetch' => $this->localizeFetch($latest),
'context' => $context,
];
}
@@ -647,6 +647,57 @@ final class FxRatesService
return $filtered;
}
private function localizeFetch(?array $fetch): ?array
{
if (!is_array($fetch)) {
return null;
}
$fetch['fetched_at_display'] = $this->formatDisplayTimestamp($fetch['fetched_at'] ?? null);
$fetch['created_at_display'] = $this->formatDisplayTimestamp($fetch['created_at'] ?? null);
return $fetch;
}
private function localizeSnapshot(?array $snapshot): ?array
{
if (!is_array($snapshot)) {
return null;
}
$snapshot['fetched_at_display'] = $this->formatDisplayTimestamp($snapshot['fetched_at'] ?? null);
if (array_key_exists('requested_at', $snapshot)) {
$snapshot['requested_at_display'] = $this->formatDisplayTimestamp($snapshot['requested_at']);
}
return $snapshot;
}
private function localizeRateResult(array $rate): array
{
$rate['fetched_at_display'] = $this->formatDisplayTimestamp($rate['fetched_at'] ?? null);
if (array_key_exists('requested_at', $rate)) {
$rate['requested_at_display'] = $this->formatDisplayTimestamp($rate['requested_at']);
}
return $rate;
}
private function formatDisplayTimestamp(mixed $value): string
{
$raw = trim((string) $value);
if ($raw === '') {
return '';
}
try {
$date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $raw, new DateTimeZone('UTC'));
if (!$date instanceof DateTimeImmutable) {
$date = new DateTimeImmutable($raw, new DateTimeZone('UTC'));
}
return $date->setTimezone($this->displayTimezone())->format('d.m.Y H:i:s');
} catch (\Throwable) {
return $raw;
}
}
private function normalizeCurrencyApiComCurrenciesPayload(array $payload): array
{
$rawCurrencies = is_array($payload['data'] ?? null) ? $payload['data'] : null;
@@ -815,4 +866,9 @@ final class FxRatesService
return new DateTimeZone('Europe/Berlin');
}
}
private function displayTimezone(): DateTimeZone
{
return $this->scheduleTimezone();
}
}