View source
<?php
namespace Drupal\google_analytics_counter;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\HttpFoundation\RedirectResponse;
use GuzzleHttp\Exception\RequestException;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Url;
class GoogleAnalyticsCounterFeed {
use StringTranslationTrait;
const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
const SCOPE = 'https://www.googleapis.com/auth/analytics.readonly https://www.google.com/analytics/feeds/';
public $response;
public $results;
public $queryPath;
public $error;
public $fromCache = FALSE;
public $accessToken;
public $refreshToken;
public $expiresAt;
protected $host = 'www.googleapis.com/analytics/v3';
protected $source = 'drupal';
protected $verifier;
protected $oAuthHost = 'www.google.com';
public function isAuthenticated() {
return !empty($this->accessToken);
}
public function __construct($token = NULL) {
$this->accessToken = $token;
}
public function createAuthUrl($client_id, $redirect_uri) {
$params = [
'response_type=code',
'redirect_uri=' . $redirect_uri,
'client_id=' . urlencode($client_id),
'scope=' . self::SCOPE,
'access_type=offline',
'approval_prompt=force',
];
$params = implode('&', $params);
return self::OAUTH2_AUTH_URL . "?{$params}";
}
protected function fetchToken($client_id, $client_secret, $redirect_uri, $refresh_token = NULL) {
if ($refresh_token) {
$params = [
'client_id=' . $client_id,
'client_secret=' . $client_secret,
'refresh_token=' . $refresh_token,
'grant_type=refresh_token',
];
}
else {
$params = [
'code=' . $_GET['code'],
'grant_type=authorization_code',
'redirect_uri=' . $redirect_uri,
'client_id=' . $client_id,
'client_secret=' . $client_secret,
];
}
try {
$client = \Drupal::httpClient();
$this->response = $client
->post(self::OAUTH2_TOKEN_URI, [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => implode('&', $params),
]);
} catch (RequestException $e) {
$this->response = $e
->getResponse();
}
if (substr($this->response
->getStatusCode(), 0, 1) == '2') {
$decoded_response = json_decode($this->response
->getBody()
->__toString(), TRUE);
$this->accessToken = $decoded_response['access_token'];
$this->expiresAt = time() + $decoded_response['expires_in'];
if (!$this->refreshToken) {
$this->refreshToken = $decoded_response['refresh_token'];
}
}
}
public function finishAuthentication($client_id, $client_secret, $redirect_uri) {
$this
->fetchToken($client_id, $client_secret, $redirect_uri);
}
public function beginAuthentication($client_id, $redirect_uri) {
$response = new RedirectResponse($this
->createAuthUrl($client_id, $redirect_uri));
return $response
->send();
}
public function refreshToken($client_id, $client_secret, $refresh_token) {
$this->refreshToken = $refresh_token;
$this
->fetchToken($client_id, $client_secret, '', $refresh_token);
}
public function revokeToken($token = NULL) {
if (!$token) {
$token = $this->refreshToken ? $this->refreshToken : $this->accessToken;
}
try {
$client = \Drupal::httpClient();
$this->response = $client
->post(self::OAUTH2_REVOKE_URI, [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => 'token=' . $token,
]);
} catch (RequestException $e) {
$this->response = $e
->getResponse();
}
if ($this->response
->getStatusCode() == 200) {
$this->accessToken = NULL;
return TRUE;
}
return FALSE;
}
public function generateAuthHeader($token = NULL) {
if ($token == NULL) {
$token = $this->accessToken;
}
return [
'Authorization' => 'Bearer ' . $token,
];
}
public function setVerifier($verifier) {
$this->verifier = $verifier;
}
public function setHost($host) {
$this->host = $host;
}
protected function setQueryPath($path) {
$this->queryPath = 'https://' . $this->host . '/' . $path;
}
public function query($url, $params, $method, $headers, $cache_options = array()) {
$params_defaults = [
'start-index' => 1,
'max-results' => 1000,
];
$params += $params_defaults;
$cache_defaults = [
'cid' => NULL,
'expire' => GoogleAnalyticsCounterHelper::cacheTime(),
'refresh' => FALSE,
];
$cache_options += $cache_defaults;
if (empty($cache_options['cid'])) {
$cache_options['cid'] = 'GoogleAnalyticsCounterFeed:' . md5(serialize(array_merge($params, [
$url,
$method,
])));
}
$cache = \Drupal::cache()
->get($cache_options['cid']);
if (!$cache_options['refresh'] && isset($cache) && !empty($cache->data)) {
$this->results = $cache->data;
$this->fromCache = TRUE;
}
else {
$this
->request($url, $params, $headers);
}
if (empty($this->error)) {
\Drupal::cache()
->set($cache_options['cid'], $this->results, $cache_options['expire']);
}
return empty($this->error);
}
protected function request($url, $params = array(), $headers = array(), $method = 'GET') {
$options = [
'method' => $method,
'headers' => $headers,
];
if (count($params) > 0) {
if ($method == 'GET') {
$url .= '?' . UrlHelper::buildQuery($params);
}
else {
$options['body'] = UrlHelper::buildQuery($params);
}
}
$client = \Drupal::httpClient();
try {
$this->response = $client
->request($method, $url, $options);
} catch (\Exception $e) {
if ($e
->getCode() == 403) {
return new RedirectResponse(Url::fromRoute('google_analytics_counter.admin_auth_form', [], [
'absolute' => TRUE,
])
->toString());
}
}
if (!empty($this->response
->getBody()) && $this->response
->getStatusCode() == '200') {
$this->results = json_decode($this->response
->getBody()
->__toString());
}
else {
if (isset($this->response) && empty($this->response
->getBody()
->__toString())) {
$this->response
->setBody('');
}
$error_vars = [
'@code' => $this->response
->getStatusCode(),
'@message' => $this->response
->getReasonPhrase(),
'@details' => strip_tags($this->response
->getBody()
->__toString()),
];
$this->error = $this
->t('Code: @code. Error: @message. Message: @details', $error_vars);
\Drupal::logger('google_analytics_counter')
->error('Code: @code. Error: @message. Message: @details', $error_vars);
}
}
public function queryAccounts($params = array(), $cache_options = array()) {
$this
->setQueryPath('management/accounts');
$this
->query($this->queryPath, $params, 'GET', $this
->generateAuthHeader(), $cache_options);
return $this;
}
public function queryWebProperties($params = array(), $cache_options = array()) {
$params += [
'account-id' => '~all',
];
$this
->setQueryPath('management/accounts/' . $params['account-id'] . '/webproperties');
$this
->query($this->queryPath, $params, 'GET', $this
->generateAuthHeader(), $cache_options);
return $this;
}
public function queryProfiles($params = array(), $cache_options = array()) {
$params += [
'account-id' => '~all',
'web-property-id' => '~all',
];
$this
->setQueryPath('management/accounts/' . $params['account-id'] . '/webproperties/' . $params['web-property-id'] . '/profiles');
$this
->query($this->queryPath, $params, 'GET', $this
->generateAuthHeader(), $cache_options);
return $this;
}
public function querySegments($params = array(), $cache_options = array()) {
$this
->setQueryPath('management/segments');
$this
->query($this->queryPath, $params, 'GET', $this
->generateAuthHeader(), $cache_options);
return $this;
}
public function queryGoals($params = array(), $cache_options = array()) {
$params += [
'account-id' => '~all',
'web-property-id' => '~all',
'profile-id' => '~all',
];
$this
->setQueryPath('management/accounts/' . $params['account-id'] . '/webproperties/' . $params['web-property-id'] . '/profiles/' . $params['profile-id'] . '/goals');
$this
->query($this->queryPath, $params, 'GET', $this
->generateAuthHeader(), $cache_options);
return $this;
}
public function queryReportFeed($params = [], $cache_options = []) {
$params += [
'profile_id' => 0,
'dimensions' => NULL,
'metrics' => 'ga:visits',
'sort_metric' => NULL,
'filters' => NULL,
'segment' => NULL,
'start_date' => NULL,
'end_date' => NULL,
'start_index' => 1,
'max_results' => 10000,
];
$parameters = [
'ids' => $params['profile_id'],
];
if (is_array($params['dimensions'])) {
$parameters['dimensions'] = implode(',', $params['dimensions']);
}
elseif ($params['dimensions'] !== NULL) {
$parameters['dimensions'] = $params['dimensions'];
}
if (is_array($params['metrics'])) {
$parameters['metrics'] = implode(',', $params['metrics']);
}
else {
$parameters['metrics'] = $params['metrics'];
}
if ($params['sort_metric'] == NULL && isset($parameters['metrics'])) {
$parameters['sort'] = $parameters['metrics'];
}
elseif (is_array($params['sort_metric'])) {
$parameters['sort'] = implode(',', $params['sort_metric']);
}
else {
$parameters['sort'] = $params['sort_metric'];
}
$start_date = '';
if (empty($params['start_date']) || !is_int($params['start_date'])) {
$start_date = date('Y-m-d');
}
elseif (is_int($params['start_date'])) {
$start_date = date('Y-m-d', $params['start_date']);
}
$parameters['start-date'] = $start_date;
$end_date = '';
if (empty($params['end_date']) || !is_int($params['end_date'])) {
$end_date = date('Y-m-d');
}
elseif (is_int($params['end_date'])) {
$end_date = date('Y-m-d', $params['end_date']);
}
$parameters['end-date'] = $end_date;
if (!empty($params['filters'])) {
$parameters['filters'] = $params['filters'];
}
if (!empty($params['segment'])) {
$parameters['segment'] = $params['segment'];
}
$parameters['start-index'] = $params['start_index'];
$parameters['max-results'] = $params['max_results'];
$this
->setQueryPath('data/ga');
if ($this
->query($this->queryPath, $parameters, 'GET', $this
->generateAuthHeader(), $cache_options)) {
$this
->sanitizeReport();
}
return $this;
}
protected function sanitizeReport() {
$this->results->rawRows = isset($this->results->rows) ? $this->results->rows : [];
$this->results->rows = [];
foreach ($this->results->rawRows as $row_key => $row_value) {
foreach ($row_value as $item_key => $item_value) {
$this->results->rows[$row_key][str_replace('ga:', '', $this->results->columnHeaders[$item_key]->name)] = $item_value;
}
}
unset($this->results->rawRows);
$this->results->rawTotals = $this->results->totalsForAllResults;
$this->results->totalsForAllResults = [];
foreach ($this->results->rawTotals as $row_key => $row_value) {
$this->results->totalsForAllResults[str_replace('ga:', '', $row_key)] = $row_value;
}
unset($this->results->rawTotals);
}
}