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

This commit is contained in:
2026-05-01 03:37:41 +02:00
parent 5a154f896b
commit c444ece852
10 changed files with 436 additions and 152 deletions

View File

@@ -44,30 +44,46 @@ final class FxService
public function convert(?float $amount, ?string $from, ?string $to): ?float
{
$shared = $this->sharedFxService();
if ($shared !== null && method_exists($shared, 'convert')) {
$converted = $shared->convert($amount, $from, $to, null, null);
return is_numeric($converted) ? (float) $converted : null;
}
return $this->convertAt($amount, $from, $to, null, null, null);
}
public function convertAt(?float $amount, ?string $from, ?string $to, ?string $at = null, ?int $windowMinutes = null, ?int $fetchId = null): ?float
{
if ($amount === null || $from === null || $to === null) {
return null;
}
$rate = $this->rate($from, $to);
$normalizedFetchId = $fetchId !== null && $fetchId > 0 ? $fetchId : null;
$shared = $this->sharedFxService();
if ($shared !== null && $normalizedFetchId !== null && method_exists($shared, 'snapshotByFetchId')) {
$snapshot = $shared->snapshotByFetchId($normalizedFetchId, strtoupper(trim((string) $from)), [strtoupper(trim((string) $to))]);
if (is_array($snapshot)) {
$resolved = $this->resolveRateFromSnapshot($snapshot, strtoupper(trim((string) $from)), strtoupper(trim((string) $to)));
if ($resolved !== null) {
return $amount * $resolved;
}
}
}
if ($shared !== null && method_exists($shared, 'convert')) {
$converted = $shared->convert($amount, $from, $to, $at, $windowMinutes);
return is_numeric($converted) ? (float) $converted : null;
}
$rate = $this->rateAt($from, $to, $at, $windowMinutes, $normalizedFetchId);
return $rate === null ? null : $amount * $rate;
}
public function rate(?string $from, ?string $to): ?float
{
$shared = $this->sharedFxService();
if ($shared !== null && method_exists($shared, 'findRate')) {
$resolved = $shared->findRate($from, $to, null, null);
return is_array($resolved) && is_numeric($resolved['rate'] ?? null) ? (float) $resolved['rate'] : null;
}
return $this->rateAt($from, $to, null, null, null);
}
public function rateAt(?string $from, ?string $to, ?string $at = null, ?int $windowMinutes = null, ?int $fetchId = null): ?float
{
$base = strtoupper(trim((string) $from));
$target = strtoupper(trim((string) $to));
$normalizedFetchId = $fetchId !== null && $fetchId > 0 ? $fetchId : null;
if ($base === '' || $target === '') {
return null;
@@ -77,7 +93,22 @@ final class FxService
return 1.0;
}
$cacheKey = $base . ':' . $target;
$shared = $this->sharedFxService();
if ($shared !== null && $normalizedFetchId !== null && method_exists($shared, 'snapshotByFetchId')) {
$snapshot = $shared->snapshotByFetchId($normalizedFetchId, $base, [$target]);
if (is_array($snapshot)) {
$resolved = $this->resolveRateFromSnapshot($snapshot, $base, $target);
if ($resolved !== null) {
return $resolved;
}
}
}
if ($shared !== null && method_exists($shared, 'findRate')) {
$resolved = $shared->findRate($from, $to, $at, $windowMinutes);
return is_array($resolved) && is_numeric($resolved['rate'] ?? null) ? (float) $resolved['rate'] : null;
}
$cacheKey = implode(':', [$base, $target, $at ?? '', (string) ($windowMinutes ?? 0), (string) ($normalizedFetchId ?? 0)]);
if (array_key_exists($cacheKey, $this->memoryCache)) {
return $this->memoryCache[$cacheKey];
}
@@ -107,6 +138,43 @@ final class FxService
return $rate;
}
public function snapshotByFetchId(int $fetchId, ?string $baseCurrency = null, ?array $symbols = null): ?array
{
if ($fetchId <= 0) {
return null;
}
$shared = $this->sharedFxService();
if ($shared !== null && method_exists($shared, 'snapshotByFetchId')) {
$snapshot = $shared->snapshotByFetchId($fetchId, $baseCurrency, $symbols);
return is_array($snapshot) ? $snapshot : null;
}
return null;
}
public function latestSnapshot(?string $baseCurrency = null, ?array $symbols = null): ?array
{
$shared = $this->sharedFxService();
if ($shared !== null && method_exists($shared, 'snapshot')) {
$snapshot = $shared->snapshot($baseCurrency, null, $symbols, null);
return is_array($snapshot) ? $snapshot : null;
}
return null;
}
public function nearestSnapshot(?string $baseCurrency, string $at, ?array $symbols = null, ?int $windowMinutes = null): ?array
{
$shared = $this->sharedFxService();
if ($shared !== null && method_exists($shared, 'nearestSnapshot')) {
$snapshot = $shared->nearestSnapshot($baseCurrency, $at, $symbols, $windowMinutes);
return is_array($snapshot) ? $snapshot : null;
}
return null;
}
public function refreshLatestRates(?array $currencies = null, string $base = 'EUR'): array
{
$shared = $this->sharedFxService();
@@ -807,4 +875,28 @@ final class FxService
return null;
}
}
private function resolveRateFromSnapshot(array $snapshot, string $from, string $to): ?float
{
$base = strtoupper(trim((string) ($snapshot['base_currency'] ?? '')));
$rates = is_array($snapshot['rates'] ?? null) ? $snapshot['rates'] : [];
if ($base === '' || $from === '' || $to === '') {
return null;
}
if ($base === $from && is_numeric($rates[$to] ?? null)) {
return (float) $rates[$to];
}
if ($base === $to && is_numeric($rates[$from] ?? null) && (float) $rates[$from] > 0) {
return 1 / (float) $rates[$from];
}
if (is_numeric($rates[$from] ?? null) && is_numeric($rates[$to] ?? null) && (float) $rates[$from] > 0) {
return (float) $rates[$to] / (float) $rates[$from];
}
return null;
}
}