Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# get your apiKey in https://retroachievements.org/settings
RETROACHIEVEMENTS_API_KEY=
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
.idea
.phpunit.cache
.phpunit.result.cache
build
composer.lock
coverage
docs
phpunit.xml
phpstan.neon
testbench.yaml
vendor
node_modules
.env
public/index.php
143 changes: 141 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/retroachievements/api/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/retroachievements/api/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/retroachievements/api.svg?style=flat-square)](https://packagist.org/packages/retroachievements/api)

## Requirements

- PHP 8.2+
- Guzzle 7.0+

## Installation

Install the package via composer:
Expand All @@ -14,16 +19,150 @@ Install the package via composer:
composer require retroachievements/api
```

## Configuration

Add your API key to your `.env` file:

```
RETROACHIEVEMENTS_API_KEY=your-api-key-here
```

You can get your API key at [retroachievements.org/settings](https://retroachievements.org/settings).

## Usage

WIP
### Standalone

in your php file add:
```php
<?php

require_once __DIR__.'/../vendor/autoload.php';

use RetroAchievements\Services\RetroAchievementsApiClient;

$api = new RetroAchievementsApiClient;
$api->setApiKey('your-api-key-here');

$profile = $api->getUserProfile('MaxMilyin');
$achievements = $api->getUserRecentAchievements('MaxMilyin', 60);

echo $profile->User;
echo $profile->TotalPoints;

foreach ($achievements as $achievement) {
echo $achievement->Title;
echo $achievement->GameTitle;
}
```

### Laravel

Publish the config file:

```shell
php artisan vendor:publish --provider="RetroAchievements\Providers\RetroAchievementsProvider"
```

### Manual Registration (if auto-discovery fails)

If the provider is not discovered automatically, add it manually to `bootstrap/providers.php` (Laravel 11+):

```php
return [
RetroAchievements\Providers\RetroAchievementsProvider::class,
];
```

Use the Facade:

```php
use RetroAchievements\Facades\RetroAchievements;

$profile = RetroAchievements::getUserProfile('MaxMilyin');
$achievements = RetroAchievements::getUserRecentAchievements('MaxMilyin', 60);
```

Switching API keys at runtime:

```php
foreach ($users as $user) {
RetroAchievements::setApiKey($user->ra_api_key);

$profile = RetroAchievements::getUserProfile($user->ra_username);
}
```

## Error Handling

```php
use RetroAchievements\Exceptions\ApiException;
use RetroAchievements\Exceptions\InvalidApiKeyException;
use RetroAchievements\Exceptions\InvalidDateException;

try {
$profile = RetroAchievements::getUserProfile('NickGoat1990');

} catch (InvalidApiKeyException $e) {
// Invalid or missing API key
} catch (InvalidDateException $e) {
// Invalid date format or range
} catch (ApiException $e) {
// General API error
}
```

## Available Methods

### User
| Method | Description |
|--------|-------------|
| `getUserProfile(string $username)` | Get user profile |
| `getUserRecentAchievements(string $username, ?int $minutes)` | Get recent achievements |
| `getAchievementsEarnedBetween(string $username, string $from, string $to)` | Get achievements earned in a date range |
| `getAchievementsEarnedOnDay(string $username, string $date)` | Get achievements earned on a specific day |
| `getUserPoints(string $username)` | Get user points |
| `getUserRankAndScore(string $username)` | Get user rank and score |
| `getUserSummary(string $username)` | Get user summary |
| `getUserCompletionProgress(string $username)` | Get user completion progress |
| `getUserAwards(string $username)` | Get user awards |
| `getUserRecentlyPlayedGames(string $username, ?int $limit)` | Get recently played games |
| `getUserWantToPlayList(string $username, ?int $limit)` | Get want to play list |
| `getUserCompletedGames(string $username)` | Get completed games |
| `getUserProgress(string $username, array $gameIds)` | Get user progress for specific games |
| `getUserClaims(string $username)` | Get user claims |
| `getUserGameRankAndScore(string $username, int $gameId)` | Get user rank and score for a specific game |

### Games & Consoles
| Method | Description |
|--------|-------------|
| `getGameInfo(int $gameId)` | Get game information |
| `getGameInfoExtended(int $gameId)` | Get extended game information |
| `getGameInfoAndUserProgress(string $username, int $gameId)` | Get game info with user progress |
| `getGameList(int $consoleId)` | Get game list for a console |
| `getConsoleIDs()` | Get all console IDs |

### Feed & Ranking
| Method | Description |
|--------|-------------|
| `getTopTenUsers()` | Get top ten users |
| `getFeedFor(string $username, int $count, int $offset)` | Get feed for a user |
| `getAchievementOfTheWeek()` | Get achievement of the week |

## Testing

```shell
composer test
```

## Quality

```shell
composer check # runs pint + phpstan + phpunit
composer fix # auto-fix code style
composer stan # phpstan only
```

## Contributing

See [Contribution Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
Expand All @@ -38,4 +177,4 @@ Please review [our security policy](../../security/policy).

## License

MIT License (MIT). See [License File](LICENSE.md).
MIT License (MIT). See [License File](LICENSE.md).
31 changes: 27 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,46 @@
"homepage": "https://github.com/retroachievements/api-php",
"license": "MIT",
"require": {
"php": "^8.2"
"php": "^8.2",
"guzzlehttp/guzzle": "^7.12"
},
"require-dev": {},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"sort-packages": true
},
"autoload": {
"psr-4": {
"RetroAchievements\\Api\\": "src"
"RetroAchievements\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests"
}
},
"scripts": {}
"extra": {
"laravel": {
"providers": [
"RetroAchievements\\Providers\\RetroAchievementsProvider"
],
"aliases": {
"RetroAchievements": "RetroAchievements\\Facades\\RetroAchievements"
}
}
},
"scripts": {
"test": "vendor/bin/phpunit --testdox",
"lint": "vendor/bin/pint --test",
"fix": "vendor/bin/pint",
"stan": "vendor/bin/phpstan analyse",
"check": ["@lint", "@stan", "@test"]
},
"require-dev": {
"laravel/framework": "^13.17",
"laravel/pint": "^1.29",
"phpstan/phpstan": "^2.2",
"phpunit/phpunit": "^13.2",
"vlucas/phpdotenv": "^5.6"
}
}
5 changes: 5 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
parameters:
level: 8
paths:
- src
ignoreErrors: []
11 changes: 11 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="Unit">
<directory>./tests/Unit</directory>
</testsuite>
</testsuites>
</phpunit>
61 changes: 61 additions & 0 deletions public/index.example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

require_once __DIR__.'/../vendor/autoload.php';

// ---------------------------------------------------------------------------
// Standalone usage
// ---------------------------------------------------------------------------

use RetroAchievements\Services\RetroAchievementsApiClient;

$api = new RetroAchievementsApiClient;
$api->setApiKey('your-api-key-here');

$profile = $api->getUserProfile('MaxMilyin');
$achievementsEarnedBetween = $api->getAchievementsEarnedBetween('MaxMilyin', '2024-01-01', '2024-01-30');
$userSummary = $api->getUserSummary('MaxMilyin', 1, 3);
$consoleIds = $api->getConsoleIDs();

var_dump($profile);
var_dump($achievementsEarnedBetween);

// ---------------------------------------------------------------------------
// Laravel bootstrap (only needed outside a Laravel project)
// ---------------------------------------------------------------------------

use Illuminate\Config\Repository;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Facade;
use RetroAchievements\Facades\RetroAchievements;
use RetroAchievements\Providers\RetroAchievementsProvider;

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__.'/../');
$dotenv->load();

$app = new Application(__DIR__.'/../');

$app->singleton('config', function () {
return new Repository([
'retroachievements' => require __DIR__.'/../src/config/retroachievements.php',
]);
});

Facade::setFacadeApplication($app);

$provider = new RetroAchievementsProvider($app);
$provider->register();
$provider->boot();

// ---------------------------------------------------------------------------
// Laravel usage
// In a real Laravel project, everything above is handled automatically.
// Just use the Facade directly:
// ---------------------------------------------------------------------------

RetroAchievements::setApiKey('your-api-key-here'); // optional if set in .env

$profile = RetroAchievements::getUserProfile('MaxMilyin');
$achievements = RetroAchievements::getUserRecentAchievements('MaxMilyin', 525600);

var_dump($profile);
var_dump($achievements);
7 changes: 7 additions & 0 deletions src/Exceptions/ApiException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

declare(strict_types=1);

namespace RetroAchievements\Exceptions;

class ApiException extends RetroAchievementsException {}
7 changes: 7 additions & 0 deletions src/Exceptions/InvalidApiKeyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

declare(strict_types=1);

namespace RetroAchievements\Exceptions;

class InvalidApiKeyException extends RetroAchievementsException {}
7 changes: 7 additions & 0 deletions src/Exceptions/InvalidDateException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

declare(strict_types=1);

namespace RetroAchievements\Exceptions;

class InvalidDateException extends RetroAchievementsException {}
9 changes: 9 additions & 0 deletions src/Exceptions/RetroAchievementsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace RetroAchievements\Exceptions;

use RuntimeException;

class RetroAchievementsException extends RuntimeException {}
Loading