Skip to content

Commit 33a6b11

Browse files
committed
feat: refactor to use Guzzle
1 parent c833f5f commit 33a6b11

8 files changed

+270
-195
lines changed

composer.json

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
{
22
"name": "retroachievements/api",
3-
"description": "RetroAchievements Web API Client",
43
"type": "library",
4+
"description": "RetroAchievements Web API Client",
5+
"license": "MIT",
56
"keywords": [
6-
"RetroAchievmenets",
7+
"RetroAchievements",
78
"retro",
89
"achievements",
910
"API"
1011
],
1112
"homepage": "https://github.com/retroachievements/api-php",
12-
"license": "MIT",
1313
"require": {
14-
"php": "^8.2"
14+
"php": "^8.2",
15+
"guzzlehttp/guzzle": "^6.5.8|^7.8.1"
1516
},
16-
"require-dev": {},
17-
"minimum-stability": "dev",
18-
"prefer-stable": true,
19-
"config": {
20-
"sort-packages": true
17+
"require-dev": {
18+
"symfony/var-dumper": "^6.4|^7.0"
2119
},
2220
"autoload": {
2321
"psr-4": {
@@ -29,5 +27,10 @@
2927
"Tests\\": "tests"
3028
}
3129
},
32-
"scripts": {}
30+
"scripts": {},
31+
"config": {
32+
"sort-packages": true
33+
},
34+
"minimum-stability": "dev",
35+
"prefer-stable": true
3336
}

src/Exceptions/GenericException.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api\Exceptions;
6+
7+
use Exception;
8+
9+
class GenericException extends Exception implements RetroAchievementsException
10+
{
11+
}

src/Exceptions/NotFoundException.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api\Exceptions;
6+
7+
use Exception;
8+
9+
class NotFoundException extends Exception implements RetroAchievementsException
10+
{
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api\Exceptions;
6+
7+
interface RetroAchievementsException
8+
{
9+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api\Exceptions;
6+
7+
use Exception;
8+
9+
class UnauthorizedException extends Exception implements RetroAchievementsException
10+
{
11+
}

src/MakesHttpRequests.php

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api;
6+
7+
use Psr\Http\Message\ResponseInterface;
8+
use RetroAchievements\Api\Exceptions\GenericException;
9+
use RetroAchievements\Api\Exceptions\NotFoundException;
10+
use RetroAchievements\Api\Exceptions\UnauthorizedException;
11+
12+
trait MakesHttpRequests
13+
{
14+
protected function get(string $uri)
15+
{
16+
return $this->request('GET', $uri);
17+
}
18+
19+
protected function post(string $uri, array $payload = [])
20+
{
21+
return $this->request('POST', $uri, $payload);
22+
}
23+
24+
protected function put(string $uri, array $payload = [])
25+
{
26+
return $this->request('PUT', $uri, $payload);
27+
}
28+
29+
protected function delete(string $uri, array $payload = [])
30+
{
31+
return $this->request('DELETE', $uri, $payload);
32+
}
33+
34+
protected function request(string $verb, string $uri, array $payload = [])
35+
{
36+
$response = $this->client->request(
37+
$verb,
38+
$uri,
39+
empty($payload) ? [] : ['form_params' => $payload]
40+
);
41+
42+
if (! $this->isSuccessful($response)) {
43+
$this->handleRequestError($response);
44+
}
45+
46+
$responseBody = (string) $response->getBody();
47+
48+
return json_decode($responseBody, true) ?: $responseBody;
49+
}
50+
51+
protected function isSuccessful(ResponseInterface $response): bool
52+
{
53+
return (int) substr((string) $response->getStatusCode(), 0, 1) === 2;
54+
}
55+
56+
protected function handleRequestError(ResponseInterface $response): void
57+
{
58+
if ($response->getStatusCode() === 404) {
59+
throw new NotFoundException((string) $response->getBody());
60+
}
61+
62+
if ($response->getStatusCode() === 401) {
63+
throw new UnauthorizedException((string) $response->getBody());
64+
}
65+
66+
throw new GenericException((string) $response->getBody());
67+
}
68+
}

src/RetroAchievements.php

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RetroAchievements\Api;
6+
7+
use GuzzleHttp\Client;
8+
9+
class RetroAchievements
10+
{
11+
use MakesHttpRequests;
12+
13+
public const API_URL = 'https://retroachievements.org/API/';
14+
15+
public const API_VERSION = 1;
16+
17+
protected Client $client;
18+
19+
public function __construct(public string $username, public string $apiKey, string $baseUri = self::API_URL)
20+
{
21+
$this->client = new Client([
22+
'base_uri' => $baseUri,
23+
'http_errors' => false,
24+
'headers' => [
25+
'Accept' => 'application/json',
26+
'Content-Type' => 'application/json',
27+
],
28+
]);
29+
}
30+
31+
public function setClient(Client $client): self
32+
{
33+
$this->client = $client;
34+
35+
return $this;
36+
}
37+
38+
public function getTopTenUsers(): mixed
39+
{
40+
return $this->getApiUrl('API_GetTopTenUsers.php');
41+
}
42+
43+
public function getGameInfo(int $gameID): mixed
44+
{
45+
return $this->getApiUrl('API_GetGame.php', [
46+
'i' => $gameID,
47+
]);
48+
}
49+
50+
public function getGameInfoExtended(int $gameID): mixed
51+
{
52+
return $this->getApiUrl('API_GetGameExtended.php', [
53+
'i' => $gameID,
54+
]);
55+
}
56+
57+
public function getConsoleIDs(): mixed
58+
{
59+
return $this->getApiUrl('API_GetConsoleIDs.php');
60+
}
61+
62+
public function getGameList(int $consoleID): mixed
63+
{
64+
return $this->getApiUrl('API_GetGameList.php', [
65+
'i' => $consoleID,
66+
]);
67+
}
68+
69+
public function getFeedFor(string $user, int $count, int $offset = 0): mixed
70+
{
71+
return $this->getApiUrl('API_GetFeed.php', [
72+
'u' => $user,
73+
'c' => $count,
74+
'o' => $offset,
75+
]);
76+
}
77+
78+
public function getUserRankAndScore(string $user): mixed
79+
{
80+
return $this->getApiUrl('API_GetUserRankAndScore.php', [
81+
'u' => $user,
82+
]);
83+
}
84+
85+
public function getUserProgress(string $user, string $gameIDCSV): mixed
86+
{
87+
$gameIDCSV = preg_replace('/\s+/', '', $gameIDCSV); // Remove all whitespace
88+
89+
return $this->getApiUrl('API_GetUserProgress.php', [
90+
'u' => $user,
91+
'i' => $gameIDCSV,
92+
]);
93+
}
94+
95+
public function getUserRecentlyPlayedGames(string $user, int $count, int $offset = 0): mixed
96+
{
97+
return $this->getApiUrl('API_GetUserRecentlyPlayedGames.php', [
98+
'u' => $user,
99+
'c' => $count,
100+
'o' => $offset,
101+
]);
102+
}
103+
104+
public function getUserSummary(string $user, int $numRecentGames): mixed
105+
{
106+
return $this->getApiUrl('API_GetUserSummary.php', [
107+
'u' => $user,
108+
'g' => $numRecentGames,
109+
'a' => 5,
110+
]);
111+
}
112+
113+
public function getGameInfoAndUserProgress(string $user, int $gameID): mixed
114+
{
115+
return $this->getApiUrl('API_GetGameInfoAndUserProgress.php', [
116+
'u' => $user,
117+
'g' => $gameID,
118+
]);
119+
}
120+
121+
public function getAchievementsEarnedOnDay(string $user, string $date): mixed
122+
{
123+
return $this->getApiUrl('API_GetAchievementsEarnedOnDay.php', [
124+
'u' => $user,
125+
'd' => $date,
126+
]);
127+
}
128+
129+
public function getAchievementsEarnedBetween(string $user, string $startDate, string $endDate): mixed
130+
{
131+
return $this->getApiUrl('API_GetAchievementsEarnedBetween.php', [
132+
'u' => $user,
133+
'f' => strtotime($startDate),
134+
't' => strtotime($endDate),
135+
]);
136+
}
137+
138+
protected function getApiUrl(string $endpoint, array $parameters = []): mixed
139+
{
140+
return $this->get(
141+
sprintf('%s?%s', $endpoint, http_build_query([
142+
'z' => $this->username,
143+
'y' => $this->apiKey,
144+
] + $parameters))
145+
);
146+
}
147+
}

0 commit comments

Comments
 (0)