Files
portal/app/app/Services/DaData/DaDataPhoneClient.php
T

94 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\DaData;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\Factory as HttpFactory;
/**
* HTTP-обёртка над DaData clean/phone (spec §3.6).
*
* POST https://cleaner.dadata.ru/api/v1/clean/phone
* Authorization: Token <key> ; X-Secret: <secret> ; body ["<phone>"]
*
* Retry — только на сетевые ошибки и 5xx (4xx → сразу DaDataException, без retry).
* Сеть/таймаут после исчерпания retry → DaDataTimeoutException; 5xx → DaDataException.
* Конвенция клиента зеркалит App\Services\Supplier\SupplierPortalClient (inject HttpFactory).
*/
class DaDataPhoneClient
{
private const URL = 'https://cleaner.dadata.ru/api/v1/clean/phone';
public function __construct(
private readonly HttpFactory $http,
) {}
public function cleanPhone(string $phone): DaDataPhoneResponse
{
$cfg = (array) config('services.dadata');
$timeoutSec = max(1, (int) round(((int) ($cfg['timeout_ms'] ?? 2000)) / 1000));
$attempts = max(1, (int) ($cfg['retries'] ?? 1) + 1);
$apiKey = (string) ($cfg['api_key'] ?? '');
$secret = (string) ($cfg['secret'] ?? '');
$lastException = null;
for ($attempt = 0; $attempt < $attempts; $attempt++) {
try {
$response = $this->http
->asJson()
->acceptJson()
->timeout($timeoutSec)
->withHeaders([
'Authorization' => 'Token '.$apiKey,
'X-Secret' => $secret,
])
->post(self::URL, [$phone]);
} catch (ConnectionException $e) {
$lastException = new DaDataTimeoutException(
'DaData connection failed: '.$e->getMessage(), 0, $e,
);
continue; // сеть → retry
}
if ($response->serverError()) {
$lastException = new DaDataException('DaData 5xx: HTTP '.$response->status());
continue; // 5xx → retry
}
if (! $response->successful()) {
// 4xx — клиентская ошибка, retry бессмыслен.
throw new DaDataException('DaData HTTP '.$response->status().': '.$response->body());
}
return $this->parse($response->json());
}
throw $lastException ?? new DaDataException('DaData failed without a response');
}
/**
* @param mixed $body декодированный JSON (ожидается массив с одним объектом)
*/
private function parse($body): DaDataPhoneResponse
{
$row = (is_array($body) && isset($body[0]) && is_array($body[0])) ? $body[0] : [];
return new DaDataPhoneResponse(
qc: isset($row['qc']) ? (int) $row['qc'] : null,
qcConflict: isset($row['qc_conflict']) ? (int) $row['qc_conflict'] : null,
type: isset($row['type']) ? (string) $row['type'] : null,
phone: isset($row['phone']) ? (string) $row['phone'] : null,
provider: isset($row['provider']) ? (string) $row['provider'] : null,
region: isset($row['region']) ? (string) $row['region'] : null,
city: isset($row['city']) ? (string) $row['city'] : null,
timezone: isset($row['timezone']) ? (string) $row['timezone'] : null,
raw: $row,
);
}
}