Skip to content

Instantly share code, notes, and snippets.

@devbanana
Created July 19, 2018 18:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devbanana/b6b014a62f9a3fe15ae2ad43ea6a36d3 to your computer and use it in GitHub Desktop.
Save devbanana/b6b014a62f9a3fe15ae2ad43ea6a36d3 to your computer and use it in GitHub Desktop.
Basic YNAB API implementation in PHP in Symfony 4
<?php
namespace App\Services;
use Symfony\Component\Security\Core\Security;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
/**
* Class to implement the YNAB API
*
* @author Brandon Olivares
*/
class YNAB
{
private $entityManager;
private $user;
public function __construct(Security $security, EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->user = $security->getUser();
if ($this->user instanceof User && $this->user->isAuthorizedWithYNAB() && new \DateTime > $this->user->getTokenExpires()) {
$this->refreshToken();
}
}
public function call(string $endpoint, array $params = [], \stdClass $body = null, string $method = null): \stdClass
{
$client = new Client([
'base_uri' => 'https://api.youneedabudget.com/v1/',
'headers' => [
'Authorization' => 'Bearer ' . ($this->user instanceof User ? $this->user->getAccessToken() : getenv('YNAB_TOKEN')),
'Accept' => 'application/json',
],
]);
$options = [
RequestOptions::QUERY => $params,
];
if ($body) {
if (!$method) {
$method = 'POST';
}
$options[RequestOptions::jSON] = $body;
} else {
$method = 'GET';
}
$response = $client->request($method, $endpoint, $options);
return json_decode($response->getBody());
}
public function authorize(string $code, string $redirect_uri): void
{
$client = new Client([
'base_uri' => 'https://app.youneedabudget.com',
]);
$response = $client->post('oauth/token', [
RequestOptions::FORM_PARAMS => [
'client_id' => getenv('YNAB_CLIENT_ID'),
'client_secret' => getenv('YNAB_CLIENT_SECRET'),
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code',
'code' => $code,
]
]);
$data = json_decode($response->getBody());
$this->setTokens($data);
}
public function refreshToken(): void
{
$client = new Client([
'base_uri' => 'https://app.youneedabudget.com',
]);
$response = $client->post('oauth/token', [
RequestOptions::FORM_PARAMS => [
'client_id' => getenv('YNAB_CLIENT_ID'),
'client_secret' => getenv('YNAB_CLIENT_SECRET'),
'grant_type' => 'refresh_token',
'refresh_token' => $this->user->getRefreshToken(),
]
]);
$data = json_decode($response->getBody());
$this->setTokens($data);
}
protected function setTokens(\stdClass $data): void
{
if (!isset($data->access_token) || !isset($data->expires_in) || !isset($data->refresh_token)) {
throw new \LogicException('Invalid response from YNAB API while trying to fetch access token.');
}
$this->user->setAccessToken($data->access_token);
$this->user->setTokenExpires((new \DateTime)
->add(new \DateInterval('PT' . $data->expires_in . 'S')));
$this->user->setRefreshToken($data->refresh_token);
$this->entityManager->flush();
}
public function formatAmount($amount)
{
return '$' . number_format(($amount >= 0 ? $amount / 1000.0 : $amount / -1000.0), 2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment