Laravel Integration
<?php
// ESFAApiClient.php
class ESFAApiClient
{
private $baseUrl;
private $authUrl;
private $apiKey;
private $secretKey;
private $currentToken;
private $client;
public function __construct($baseUrl, $authUrl, $apiKey, $secretKey)
{
$this->baseUrl = rtrim($baseUrl, '/');
$this->authUrl = rtrim($authUrl, '/');
$this->apiKey = $apiKey;
$this->secretKey = $secretKey;
$this->client = new \GuzzleHttp\Client();
}
private function getValidToken()
{
if (!$this->currentToken || $this->isTokenExpired($this->currentToken)) {
$this->currentToken = $this->authenticate();
}
return $this->currentToken['token'];
}
private function isTokenExpired($tokenData)
{
$expiresAt = new DateTime($tokenData['expires']);
$now = new DateTime();
$buffer = new DateInterval('PT5M'); // 5 minutes
return $now >= $expiresAt->sub($buffer);
}
private function authenticate()
{
$response = $this->client->post($this->authUrl . '/v1/oauth/token/machine', [
'json' => [
'apiKey' => $this->apiKey,
'secretKey' => $this->secretKey,
],
'headers' => [
'Content-Type' => 'application/json',
],
]);
$data = json_decode($response->getBody(), true);
return $data['data'];
}
private function makeRequest($method, $endpoint, $options = [])
{
$token = $this->getValidToken();
$url = $this->baseUrl . $endpoint;
$defaultOptions = [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
];
$options = array_merge_recursive($defaultOptions, $options);
try {
$response = $this->client->request($method, $url, $options);
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getResponse()->getStatusCode() === 401) {
// Retry with fresh token
$this->currentToken = $this->authenticate();
$options['headers']['Authorization'] = 'Bearer ' . $this->currentToken['token'];
$response = $this->client->request($method, $url, $options);
} else {
throw $e;
}
}
if ($response->getStatusCode() === 204) {
return null;
}
return json_decode($response->getBody(), true);
}
public function getMatch($gameCode, $matchId)
{
return $this->makeRequest('GET', "/api/v1/games/{$gameCode}/matches/{$matchId}");
}
public function finishMatch($gameCode, $matchId, $results)
{
return $this->makeRequest('POST', "/api/v1/games/{$gameCode}/matches/{$matchId}/finish", [
'json' => ['results' => $results],
]);
}
}
// MatchController.php (Laravel)
class MatchController extends Controller
{
private $esfaClient;
public function __construct()
{
$this->esfaClient = new ESFAApiClient(
config('services.esfa.base_url'),
config('services.esfa.auth_url'),
config('services.esfa.api_key'),
config('services.esfa.secret_key')
);
}
public function getMatch($gameCode, $matchId)
{
try {
$match = $this->esfaClient->getMatch($gameCode, $matchId);
return response()->json($match);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$statusCode = $e->getResponse()->getStatusCode();
switch ($statusCode) {
case 404:
return response()->json(['error' => 'Match not found'], 404);
case 410:
return response()->json(['error' => 'Match expired'], 410);
default:
return response()->json(['error' => 'Client error'], $statusCode);
}
} catch (Exception $e) {
\Log::error('Error getting match: ' . $e->getMessage());
return response()->json(['error' => 'Internal server error'], 500);
}
}
public function finishMatch(Request $request, $gameCode, $matchId)
{
$request->validate([
'results' => 'required|array|min:1',
'results.*.playerId' => 'required|string',
'results.*.place' => 'required|integer|min:1',
'results.*.score' => 'required|numeric',
]);
try {
$this->esfaClient->finishMatch($gameCode, $matchId, $request->results);
return response()->noContent();
} catch (\GuzzleHttp\Exception\ClientException $e) {
$statusCode = $e->getResponse()->getStatusCode();
switch ($statusCode) {
case 400:
return response()->json(['error' => 'Invalid results data'], 400);
case 404:
return response()->json(['error' => 'Match not found'], 404);
case 409:
return response()->json(['error' => 'Match already finished'], 409);
default:
return response()->json(['error' => 'Client error'], $statusCode);
}
} catch (Exception $e) {
\Log::error('Error finishing match: ' . $e->getMessage());
return response()->json(['error' => 'Internal server error'], 500);
}
}
}