Files
BetiX/app/Services/BackendHttpClient.php
Dolo 0280278978
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
Initialer Laravel Commit für BetiX
2026-04-04 18:01:50 +02:00

108 lines
4.0 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Request as HttpRequest;
use Illuminate\Support\Facades\Http;
class BackendHttpClient
{
private string $base;
private string $token;
private float $timeout;
public function __construct()
{
// Choose base URL with testing-friendly priority so Http::fake() in tests can intercept
$envUrl = env('API_BASE_URL');
$appUrl = config('app.api_url');
$serviceUrl = config('services.backend.base');
if (app()->environment('testing')) {
// In tests, prefer the services config so test fakes using config('services.backend.base') match
// IMPORTANT: If config('services.backend.base') contains /api at the end, test fakes often omit it.
// We'll strip /api from the end of the base URL to match standard Http::fake() patterns in this project.
$base = (string) ($serviceUrl ?: ($envUrl ?: ($appUrl ?: 'http://casinoapi.test')));
$this->base = rtrim(preg_replace('/\/api\/?$/', '', $base), '/');
} else {
// In non-testing, prefer explicit ENV override, then services config, then app config
$this->base = rtrim((string) ($envUrl ?: ($serviceUrl ?: ($appUrl ?: 'http://casinoapi.test/api'))), '/');
}
$this->token = (string) config('services.backend.token');
$this->timeout = (float) config('services.backend.timeout', 8.0);
}
/**
* Issue a GET request with standard headers and optional retry policy.
*/
public function get(HttpRequest $request, string $path, array $query = [], bool $retry = true)
{
$req = $this->baseRequest($request)->acceptJson();
if ($retry) {
// Retry 2x on timeout/5xx
$req = $req->retry(2, 100, throw: false);
}
return $req->get($this->url($path), $query);
}
/**
* Issue a POST request with standard headers (no retries by default).
*/
public function post(HttpRequest $request, string $path, array $data = [])
{
return $this->baseRequest($request)->acceptJson()->post($this->url($path), $data);
}
public function patch(HttpRequest $request, string $path, array $data = [])
{
return $this->baseRequest($request)->acceptJson()->patch($this->url($path), $data);
}
public function delete(HttpRequest $request, string $path, array $data = [])
{
return $this->baseRequest($request)->acceptJson()->asForm()->delete($this->url($path), $data);
}
/**
* Multipart POST (file upload) with standard headers.
*/
public function postMultipart(HttpRequest $request, string $path, array $fields, $file, string $fileField = 'file', ?string $filename = null)
{
$pending = $this->baseRequest($request);
if ($file) {
$stream = fopen($file->getRealPath(), 'r');
$pending = $pending->attach($fileField, $stream, $filename ?: $file->getClientOriginalName());
}
foreach ($fields as $k => $v) {
if ($v === null) continue;
$pending = $pending->asMultipart();
}
return $pending->post($this->url($path), $fields);
}
private function url(string $path): string
{
return $this->base . '/' . ltrim($path, '/');
}
private function baseRequest(HttpRequest $request): PendingRequest
{
$user = $request->user();
$userId = $user?->id ? (string) $user->id : '';
$ua = (string) $request->header('User-Agent', '');
$sid = (string) $request->session()->getId();
$deviceHash = hash('sha256', $ua . '|' . $sid);
$ipHash = hash('sha256', (string) $request->ip());
return Http::withHeaders([
'Authorization' => 'Bearer ' . $this->token,
'X-User-Id' => $userId,
'X-User-Device' => $deviceHash,
'X-User-IP' => $ipHash,
'Accept' => 'application/json',
])->timeout($this->timeout);
}
}