Files
bij/app/Services/ApiClient.php
2026-04-21 05:59:39 +07:00

220 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use CodeIgniter\HTTP\CURLRequest;
use Config\Services;
use Throwable;
/**
* Klien HTTP ke API internal (`/api/mobile/*` dan `/api/admin/*`).
* Controller admin web tidak mengakses DB; hanya memanggil API lewat kelas ini.
*/
class ApiClient
{
private CURLRequest $client;
public function __construct(?CURLRequest $client = null)
{
$this->client = $client ?? Services::curlrequest([
'timeout' => 30,
'http_errors' => false,
]);
}
/**
* @param array<string, scalar|null> $formData
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function postMobile(string $method, array $formData = []): array
{
helper(['url']);
return $this->post('api/mobile/' . ltrim($method, '/'), $formData);
}
/**
* @param array<string, scalar|null> $formData
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function postMobileWithToken(string $method, string $token, array $formData = []): array
{
$formData['token'] = $token;
return $this->postMobile($method, $formData);
}
/**
* GET ke `/api/admin/{path}` — token ditambahkan ke query string.
*
* @param array<string, scalar|null> $query
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function getAdmin(string $path, ?string $token, array $query = []): array
{
helper(['url']);
if ($token !== null && $token !== '') {
$query['token'] = $token;
}
$forward = $this->adminInternalHeaders();
if (($forward['Cookie'] ?? '') !== '' && session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
return $this->get('api/admin/' . ltrim($path, '/'), $query, $forward);
}
/**
* POST form ke `/api/admin/{path}`.
*
* @param array<string, scalar|null> $formData
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function postAdmin(string $path, ?string $token, array $formData = []): array
{
helper(['url']);
if ($token !== null && $token !== '') {
$formData['token'] = $token;
}
$forward = $this->adminInternalHeaders();
if (($forward['Cookie'] ?? '') !== '' && session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
return $this->post('api/admin/' . ltrim($path, '/'), $formData, $forward);
}
/**
* GET generik (relatif terhadap root site, mis. `api/admin/pegawai`).
*
* @param array<string, scalar|null> $query
* @param array<string, string> $extraHeaders
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function get(string $path, array $query = [], array $extraHeaders = []): array
{
helper(['url']);
$url = base_url(ltrim($path, '/'));
$base = $this->emptyResult();
$headers = array_merge(
['Accept' => 'application/json'],
$extraHeaders
);
try {
$response = $this->client->get($url, [
'query' => $query,
'headers' => $headers,
]);
} catch (Throwable $e) {
$base['error'] = $e->getMessage();
return $base;
}
return $this->fillFromResponse($base, $response->getStatusCode(), $response->getBody());
}
/**
* POST `application/x-www-form-urlencoded`.
*
* @param array<string, scalar|null> $formData
* @param array<string, string> $extraHeaders
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
public function post(string $path, array $formData = [], array $extraHeaders = []): array
{
helper(['url']);
$url = base_url(ltrim($path, '/'));
$base = $this->emptyResult();
$headers = array_merge(
['Accept' => 'application/json'],
$extraHeaders
);
try {
$response = $this->client->post($url, [
'form_params' => $formData,
'headers' => $headers,
]);
} catch (Throwable $e) {
$base['error'] = $e->getMessage();
return $base;
}
return $this->fillFromResponse($base, $response->getStatusCode(), $response->getBody());
}
/**
* Teruskan cookie browser ke hit internal `/api/admin/*` agar sesi panel sama.
*
* @return array<string, string>
*/
private function adminInternalHeaders(): array
{
$cookie = Services::request()->getHeaderLine('Cookie');
return $cookie !== '' ? ['Cookie' => $cookie] : [];
}
/**
* @param array<string, mixed>|null $json
*/
public static function isSuccess(?array $json): bool
{
return is_array($json) && (int) ($json['status'] ?? 0) === 1;
}
/**
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
private function emptyResult(): array
{
return [
'transport_ok' => false,
'http_code' => 0,
'json' => null,
'error' => null,
'raw' => '',
];
}
/**
* @param array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string} $base
*
* @return array{transport_ok: bool, http_code: int, json: array<string, mixed>|null, error: string|null, raw: string}
*/
private function fillFromResponse(array $base, int $statusCode, string $body): array
{
$base['http_code'] = $statusCode;
$base['raw'] = $body;
$base['transport_ok'] = $statusCode === 200;
$decoded = json_decode($body, true);
if (! is_array($decoded)) {
$base['error'] = 'Respons bukan JSON objek';
return $base;
}
$base['json'] = $decoded;
return $base;
}
}