OpenXE/classes/Modules/GoogleApi/Service/GoogleAccountGateway.php
2021-05-21 08:49:41 +02:00

324 lines
9.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Xentral\Modules\GoogleApi\Service;
use Exception;
use Xentral\Components\Database\Database;
use Xentral\Components\Database\SqlQuery\SelectQuery;
use Xentral\Modules\GoogleApi\Data\GoogleAccessTokenData;
use Xentral\Modules\GoogleApi\Data\GoogleAccountPropertyValue;
use Xentral\Modules\GoogleApi\Data\GoogleAccountPropertyCollection;
use Xentral\Modules\GoogleApi\Data\GoogleAccountData;
use Xentral\Modules\GoogleApi\Exception\GoogleAccountGatewayException;
use Xentral\Modules\GoogleApi\Exception\GoogleAccountNotFoundException;
use Xentral\Modules\GoogleApi\Exception\NoAccessTokenException;
use Xentral\Modules\GoogleApi\GoogleScope;
final class GoogleAccountGateway
{
/** @var Database $db */
private $db;
/**
* @param Database $database
*/
public function __construct(Database $database)
{
$this->db = $database;
}
/**
* @param int $id
*
* @return bool
*/
public function existsAccount(int $id): bool
{
$sql = 'SELECT ga.id FROM `google_account` AS `ga` WHERE ga.id = :id';
$resultId = $this->db->fetchValue($sql, ['id' => $id]);
return $resultId === $id;
}
/**
* @param int $id
*
* @throws GoogleAccountNotFoundException
*
* @return GoogleAccountData
*/
public function getAccount(int $id): GoogleAccountData
{
$query = $this->buildAccountQuery()
->where('ga.id = :id');
$values = ['id' => $id];
$account = $this->queryAccount($query, $values);
if ($account === null) {
throw new GoogleAccountNotFoundException('Google Account not Available.');
}
return $account;
}
/**
* @param int $userId
*
* @throws GoogleAccountNotFoundException
*
* @return GoogleAccountData
*/
public function getAccountByUser(int $userId): GoogleAccountData
{
$query = $this->buildAccountQuery()
->where('ga.user_id = :user_id');
$values = ['user_id' => $userId];
$account = $this->queryAccount($query, $values);
if ($account === null) {
throw new GoogleAccountNotFoundException(
sprintf('No Google account found for user "%s"', $userId)
);
}
return $account;
}
/**
* @param string $email
*
* @throws GoogleAccountNotFoundException
*
* @return GoogleAccountData
*/
public function getAccountByGmailAddress(string $email): GoogleAccountData
{
try {
$query = $this->buildAccountQuery()
->join('', 'google_account_property AS gp', 'ga.id = gp.google_account_id')
->where("gp.varname = :varname AND gp.value = :email");
$values = ['varname' => 'gmail_address', 'email' => $email];
$account = $this->queryAccount($query, $values);
} catch (Exception $e) {
throw new GoogleAccountNotFoundException($e->getMessage(), $e->getCode(), $e);
}
if ($account === null) {
throw new GoogleAccountNotFoundException(
sprintf('No Google Account found for email address "%s"', $email)
);
}
return $account;
}
/**
* Gets all accounts that have a certain scope
*
* @param string $scope
*
* @return GoogleAccountData[]|array
*/
public function getAccountsByScope(string $scope): array
{
try {
$query = $this->buildAccountQuery()
->join('', 'google_account_scope AS gs', 'ga.id = gs.google_account_id')
->where('gs.scope = :scope');
$values = ['scope' => $scope];
$rows = $this->db->fetchAll($query->getStatement(), $values);
$accounts = [];
foreach ($rows as $row) {
$accounts[] = GoogleAccountData::fromDbState($row);
}
return $accounts;
} catch (Exception $e) {
throw new GoogleAccountGatewayException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* @param int $addressId
*
* @throws GoogleAccountGatewayException
*
* @return GoogleAccountData|null
*/
public function tryGetAccountByAddress(int $addressId): ?GoogleAccountData
{
try {
$query = $this->buildAccountQuery()
->join('', 'user AS u', 'ga.user_id = u.id')
->where('u.adresse = :address_id');
$values = ['address_id' => $addressId];
return $this->queryAccount($query, $values);
} catch (Exception $e) {
throw new GoogleAccountGatewayException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* @param int $accountId
*
* @throws NoAccessTokenException
*
* @return GoogleAccessTokenData
*/
public function getAccessToken(int $accountId): GoogleAccessTokenData
{
$query = $this->buildTokenQuery()
->where('gt.google_account_id = :account_id');
$values = ['account_id' => $accountId];
$token = $this->queryToken($query, $values);
if ($token === null) {
throw new NoAccessTokenException(
sprintf('No access token for account "%s" available.', $accountId)
);
}
return $token;
}
/**
* @param int $accountId
* @param string $scope
*
* @return bool
*/
public function hasAccountScope(int $accountId, string $scope): bool
{
$scopes = $this->getScopes($accountId);
if (in_array($scope, $scopes, true)) {
return true;
}
return false;
}
/**
* @param int $accountId
*
* @return string[] available scopes of the account
*/
public function getScopes(int $accountId): array
{
$sql = 'SELECT gs.id, gs.scope FROM `google_account_scope` AS `gs` WHERE gs.google_account_id = :account_id';
$pairs = $this->db->fetchPairs($sql, ['account_id' => $accountId]);
if (!is_array($pairs) || count($pairs) === 0) {
return [];
}
return array_values($pairs);
}
/**
* Will be removed after Dec 31. 2020
*
* @deprecated
*
* @codeCoverageIgnore
*
* @return GoogleAccountData
*/
public function getCloudPrintAccount(): GoogleAccountData
{
$accounts = $this->getAccountsByScope(GoogleScope::CLOUDPRINT);
if (count($accounts) < 1) {
throw new GoogleAccountNotFoundException('No cloud printing account available.');
}
return $accounts[0];
}
/**
* @param int $accountId
*
* @return GoogleAccountPropertyCollection
*/
public function getAccountProperties(int $accountId): GoogleAccountPropertyCollection
{
$sql = 'SELECT gp.id, gp.google_account_id, gp.varname, gp.value
FROM `google_account_property` AS `gp`
WHERE gp.google_account_id = :account_id';
$result = $this->db->fetchAll($sql, ['account_id'=> $accountId]);
if (!is_array($result) || count($result) === 0) {
return new GoogleAccountPropertyCollection([]);
}
$properties = [];
foreach ($result as $row) {
$properties[] = GoogleAccountPropertyValue::fromDbState($row);
}
return new GoogleAccountPropertyCollection($properties);
}
/**
* @return SelectQuery
*/
private function buildAccountQuery(): SelectQuery
{
return $this->db->select()
->cols(
[
'ga.id',
'ga.user_id',
'ga.refresh_token',
'ga.identifier',
]
)
->from('google_account AS ga');
}
/**
* @param SelectQuery $query
* @param array $bindValues
*
* @return GoogleAccountData|null
*/
private function queryAccount(SelectQuery $query, $bindValues = []): ?GoogleAccountData
{
$sql = $query->getStatement();
$resultSet = $this->db->fetchRow($sql, $bindValues);
if (empty($resultSet)) {
return null;
}
return GoogleAccountData::fromDbState($resultSet);
}
/**
* @return SelectQuery
*/
private function buildTokenQuery(): SelectQuery
{
return $this->db->select()
->cols(
[
'gt.google_account_id',
'gt.token',
'gt.expires',
]
)
->from('google_access_token AS gt');
}
/**
* @param SelectQuery $query
* @param array $bindValues
*
* @return GoogleAccessTokenData|null
*/
private function queryToken(SelectQuery $query, $bindValues = []): ?GoogleAccessTokenData
{
$sql = $query->getStatement();
$resultSet = $this->db->fetchRow($sql, $bindValues);
if (empty($resultSet)) {
return null;
}
return GoogleAccessTokenData::fromDbState($resultSet);
}
}