Files
SkinbaseNova/app/Services/Countries/CountryRemoteProvider.php
2026-03-20 21:17:26 +01:00

116 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Countries;
use Illuminate\Http\Client\Factory as HttpFactory;
use RuntimeException;
final class CountryRemoteProvider implements CountryRemoteProviderInterface
{
public function __construct(
private readonly HttpFactory $http,
) {
}
public function fetchAll(): array
{
$endpoint = trim((string) config('skinbase-countries.endpoint', ''));
if ($endpoint === '') {
throw new RuntimeException('Country sync endpoint is not configured.');
}
$response = $this->http->acceptJson()
->connectTimeout(max(1, (int) config('skinbase-countries.connect_timeout', 5)))
->timeout(max(1, (int) config('skinbase-countries.timeout', 10)))
->retry(
max(0, (int) config('skinbase-countries.retry_times', 2)),
max(0, (int) config('skinbase-countries.retry_sleep_ms', 250)),
throw: false,
)
->get($endpoint);
if (! $response->successful()) {
throw new RuntimeException(sprintf('Country sync request failed with status %d.', $response->status()));
}
$payload = $response->json();
if (! is_array($payload)) {
throw new RuntimeException('Country sync response was not a JSON array.');
}
return $this->normalizePayload($payload);
}
public function normalizePayload(array $payload): array
{
$normalized = [];
foreach ($payload as $record) {
if (! is_array($record)) {
continue;
}
$country = $this->normalizeRecord($record);
if ($country !== null) {
$normalized[] = $country;
}
}
return $normalized;
}
/**
* @param array<string, mixed> $record
* @return array<string, mixed>|null
*/
private function normalizeRecord(array $record): ?array
{
$iso2 = strtoupper(trim((string) ($record['cca2'] ?? $record['iso2'] ?? '')));
if (! preg_match('/^[A-Z]{2}$/', $iso2)) {
return null;
}
$iso3 = strtoupper(trim((string) ($record['cca3'] ?? $record['iso3'] ?? '')));
$iso3 = preg_match('/^[A-Z]{3}$/', $iso3) ? $iso3 : null;
$numericCode = trim((string) ($record['ccn3'] ?? $record['numeric_code'] ?? ''));
$numericCode = preg_match('/^\d{1,3}$/', $numericCode)
? str_pad($numericCode, 3, '0', STR_PAD_LEFT)
: null;
$name = $record['name'] ?? [];
$nameCommon = trim((string) ($name['common'] ?? $record['name_common'] ?? ''));
if ($nameCommon === '') {
return null;
}
$nameOfficial = trim((string) ($name['official'] ?? $record['name_official'] ?? ''));
$flags = $record['flags'] ?? [];
$flagSvgUrl = trim((string) ($flags['svg'] ?? $record['flag_svg_url'] ?? ''));
$flagPngUrl = trim((string) ($flags['png'] ?? $record['flag_png_url'] ?? ''));
$flagEmoji = trim((string) ($record['flag'] ?? $record['flag_emoji'] ?? ''));
$region = trim((string) ($record['region'] ?? ''));
$subregion = trim((string) ($record['subregion'] ?? ''));
return [
'iso2' => $iso2,
'iso3' => $iso3,
'numeric_code' => $numericCode,
'name_common' => $nameCommon,
'name_official' => $nameOfficial !== '' ? $nameOfficial : null,
'region' => $region !== '' ? $region : null,
'subregion' => $subregion !== '' ? $subregion : null,
'flag_svg_url' => $flagSvgUrl !== '' ? $flagSvgUrl : null,
'flag_png_url' => $flagPngUrl !== '' ? $flagPngUrl : null,
'flag_emoji' => $flagEmoji !== '' ? $flagEmoji : null,
];
}
}