quickbooks_api-8.x-1.0-beta4/src/QuickbooksService.php
src/QuickbooksService.php
<?php
namespace Drupal\quickbooks_api;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Url;
use QuickBooksOnline\API\DataService\DataService;
use QuickBooksOnline\API\PlatformService\PlatformService;
/**
* Exfiltrate the Quickbooks DataService for use in custom modules.
*/
class QuickbooksService {
public const CONFIG_KEY = 'quickbooks_api.settings';
public const STATE_ACCESS_TOKEN = 'quickbooks_api.access_token';
public const STATE_REFRESH_TOKEN = 'quickbooks_api.refresh_token';
public const STATE_ACCESS_TOKEN_EXPIRY = 'quickbooks_api.access_token_expiry';
public const STATE_REFRESH_EXPIRY = 'quickbooks_api.refresh_token_expiry';
public const STATE_OAUTH_SECURITY = 'quickbooks_api.oauth_route_security';
public const EXPIRY_BUFFER = 60;
/**
* QBO DataService.
*
* @var \QuickBooksOnline\API\DataService\DataService|null
*/
protected DataService|null $ds = NULL;
/**
* QBO Platform Service.
*
* @var \QuickBooksOnline\API\PlatformService\PlatformService|null
*/
protected PlatformService|null $platformService = NULL;
/**
* Constructs the service.
*
* @param \Drupal\Core\State\StateInterface $state
* Drupal State API.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* Drupal Configuration Factory Service.
* @param \Drupal\Component\Datetime\TimeInterface $time
* Drupal Time Service.
* @param \Drupal\Core\Logger\LoggerChannelInterface $log
* Quickbooks API log channel.
*/
public function __construct(protected StateInterface $state, protected ConfigFactoryInterface $configFactory, protected TimeInterface $time, protected LoggerChannelInterface $log) {}
/**
* Create a QBO API DataService.
*
* @return \QuickBooksOnline\API\DataService\DataService|null
* A QBO API Data Service client, NULL if not configuration.
*/
public function dataService() : ?DataService {
$access_token_expiry = $this->state->get(self::STATE_ACCESS_TOKEN_EXPIRY);
$refresh_token = $this->state->get(self::STATE_REFRESH_TOKEN);
try {
$settings = $this->buildSettings();
$this->ds = DataService::Configure($settings);
}
catch (\Exception $exception) {
$this->log->warning($exception->getMessage());
return NULL;
}
// Disable logging requests and responses.
$this->ds->disableLog();
// Refresh the access token if necessary.
if ($access_token_expiry < $this->time->getCurrentTime()) {
$helper = $this->ds->getOAuth2LoginHelper();
// Check for updates on the tokens.
try {
$tokens = $helper->refreshToken();
}
catch (\Exception $exception) {
// Fail out if something goes wrong.
// @todo Delete refresh state if exception is invalid token related?
$this->log->notice($exception->getMessage());
return NULL;
}
// Update the tokens in the data service.
$this->ds->updateOAuth2Token($tokens);
// Set the new access token and expiry to state.
$this->state->set(self::STATE_ACCESS_TOKEN, $tokens->getAccessToken());
$this->state->set(self::STATE_ACCESS_TOKEN_EXPIRY, self::addTokenBuffer(strtotime($tokens->getAccessTokenExpiresAt())));
$this->log->info("Quickbooks API access token updated");
// Update the refresh token if necessary.
if ($refresh_token !== $tokens->getRefreshToken()) {
$this->state->set(self::STATE_REFRESH_TOKEN, $tokens->getRefreshToken());
$this->state->set(self::STATE_REFRESH_EXPIRY, self::addTokenBuffer(strtotime($tokens->getRefreshTokenExpiresAt())));
$this->log->info("Quickbooks API refresh token updated");
}
}
return $this->ds;
}
/**
* Builds the settings for the data service.
*
* @return array
* Returns the DataService settings array.
*/
public function buildSettings() : array {
$access_token = $this->state->get(self::STATE_ACCESS_TOKEN);
$refresh_token = $this->state->get(self::STATE_REFRESH_TOKEN);
$config = $this->configFactory->get(self::CONFIG_KEY);
$company_id = $config->get('company_id');
$client_id = $config->get('client_id');
$client_secret = $config->get('client_secret');
$environment = $config->get('environment');
// Validate everything necessary to continue.
if (!$company_id || !$client_id || !$client_secret || !$environment || !$refresh_token) {
throw new \Exception("Connection to Quickbooks Online is not yet established. Please configure your connection.");
}
$oauth_route = Url::fromRoute('quickbooks_api.oauth');
return [
'QBORealmID' => $company_id,
'ClientID' => $client_id,
'ClientSecret' => $client_secret,
'auth_mode' => 'oauth2',
'baseUrl' => $environment,
'scope' => 'com.intuit.quickbooks.accounting',
'AccessToken' => $access_token,
'RefreshToken' => $refresh_token,
'redirectURL' => $oauth_route->setAbsolute(TRUE)->toString(),
];
}
/**
* Adds a time buffer to token expiration.
*
* @param int $expiry
* The actual expiry time.
*
* @return int
* Returns the buffered expiry timestamp.
*/
public static function addTokenBuffer(int $expiry) {
return $expiry - self::EXPIRY_BUFFER;
}
}
