getPostedData();
/** user params **/
$view_id = $data['view_id'];
if (empty($view_id)) {
$msg = 'Post-data is invalid, empty `view_id` value';
throw new Exception(ErrorCodes::DATA_NOT_FOUND, $msg, ['view_id' => $view_id]);
}
$result['view_id'] = $view_id;
try {
putenv('GOOGLE_APPLICATION_CREDENTIALS=/var/www/phalcon/'.self::SECRET_JSON);
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->setScopes([self::SCOPE]);
$analytics = new Google_Service_AnalyticsReporting($client);
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($view_id);
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests(array($request));
$analytics->reports->batchGet($body);
}
catch (\Exception $e) {
if ($e->getCode() == 403) {
$result['status'] = 'error';
return $result;
}
else {
return $e->getMessage();
}
}
$result['status'] = 'success';
return $result;
}
/**
* Main action for /ga request. Send it google report api.
*
* @return array
*/
public function getAction() {
/** user params **/
$user_id = $this->request->get('user_id')?? '1';
$view_id = $this->request->get('view_id');
$chart = $this->request->get('chart') ?? false;
/** google params **/
$get_metrics = $this->request->get('metric') ?? 'users';
$get_dimensions = $this->request->get('dimension');
$get_start_date = $this->request->get('start') ?? '30daysAgo';
$get_end_date = $this->request->get('end') ?? 'today';
$filter_expression = $this->request->get('filter');
$sort = $this->request->get('sort');
$sort_type = $this->request->get('sort_type');
$max_result = $this->request->get('max_result');
/** if empty $_GET["view_id"] send request to all projects in user's model **/
if (empty($view_id)) {
$result = [];
$projects = Project::find(['user_id' => $user_id]);
foreach ($projects as $project) {
$view_id = (string)$project->ga_view_id;
if (!empty($view_id)) {
$result[] = $this->sendGaRequest(
$project->name,
$project->id,
$view_id,
$get_metrics,
$get_dimensions,
$get_start_date,
$get_end_date,
$chart,
$filter_expression,
$sort,
$sort_type,
$max_result
);
}
}
}
else {
$project = Project::findFirst([
"ga_view_id = '$view_id'",
]);
$result = $this->sendGaRequest(
$project->name,
$project->id,
$view_id,
$get_metrics,
$get_dimensions,
$get_start_date,
$get_end_date,
$chart,
$filter_expression,
$sort,
$sort_type,
$max_result
);
}
/** --------------------------------------------------------------- **/
return $result;
}
/**
* Send request to Google Analytics Reporting API
*
* @param string $project_name
* @param int $project_id
* @param string $view
* @param string $get_metrics
* @param string $get_dimensions
* @param string $start
* @param string $end
* @param bool $chart
* @param string $filter_expression
* @param string $sort
* @param string $sort_type
* @param int $max_result
* @return array
*/
public function sendGaRequest($project_name, $project_id, $view, $get_metrics, $get_dimensions, $start, $end, $chart = false, $filter_expression = null, $sort = null, $sort_type = 'desc', $max_result = 50000) {
putenv('GOOGLE_APPLICATION_CREDENTIALS=/var/www/phalcon/'.self::SECRET_JSON);
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->setScopes([self::SCOPE]);
$analytics = new Google_Service_AnalyticsReporting($client);
/** Create the DateRange object. **/
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate($start);
$dateRange->setEndDate($end);
/** ---------------------------- **/
/** Create the Metrics object. **/
$metrics = [];
$get_metrics = explode(',', $get_metrics);
foreach ($get_metrics as $metric) {
$metrics_obj = new Google_Service_AnalyticsReporting_Metric();
$metrics_obj->setExpression('ga:'.$metric);
$metrics_obj->setAlias('ga:'.$metric);
$metrics[] = $metrics_obj;
}
/** -------------------------- **/
/** Create the Dimensions object. **/
if (!empty($get_dimensions)) {
$dimensions = [];
$get_dimensions = explode(',', $get_dimensions);
foreach ($get_dimensions as $dimension) {
$dimension_obj = new Google_Service_AnalyticsReporting_Dimension();
$dimension_obj->setName("ga:".$dimension);
$dimensions[] = $dimension_obj;
}
}
/** ----------------------------- **/
/** Create the ReportRequest object. **/
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($view);
$request->setPageSize($max_result);
$request->setDateRanges($dateRange);
$request->setIncludeEmptyRows(true);
/** Create the Ordering **/
if (isset($sort)) {
$ordering = new Google_Service_AnalyticsReporting_OrderBy();
$ordering->setFieldName("ga:".$sort);
$ordering->setOrderType("VALUE");
$ordering->setSortOrder("DESCENDING");
if ($sort_type == 'asc') {
$ordering->setSortOrder("ASCENDING");
}
$request->setOrderBys($ordering);
}
/** --------------- **/
if (!empty($dimensions)) {
$request->setDimensions(array($dimensions));
}
$request->setMetrics(array($metrics));
if (!empty($filter_expression)) {
$request->setFiltersExpression("ga:".$filter_expression);
}
/** compute days in request **/
$request_date['start'] = new DateTime(date('d.m.Y', strtotime($request->getDateRanges()['startDate'])));
$request_date['end'] = new DateTime(date('d.m.Y', strtotime($request->getDateRanges()['endDate'])));
$request_days = (date_diff($request_date['start'], $request_date['end'])->days)+1;
/** ----------------------- **/
$request_dim = $request->getDimensions();
if (count($request_dim[0]) == 2) {
$request_dim = $request_dim[0][1]->name;
}
else {
$request_dim = $request_dim[0][0]->name;
}
$iterations = self::countIterations($request_dim, $request_days);
/** ---------------------------- **/
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests(array($request));
$response = $analytics->reports->batchGet($body);
//can be refactored (code below, 2 rows)
$response = $response->toSimpleObject();
$response = $response->reports[0]['data']['rows'];
$custom_fields = ['name' => $project_name, 'view_id' => (int)$view, 'id' => $project_id];
if ($chart) {
$result = self::responseDataTransform($response, $iterations, $request_dim, $custom_fields);
$result = self::chartTransform($result);
} else {
$result = self::responseDataTransform($response, $iterations, $request_dim, $custom_fields);
}
return $result;
}
/**
* Data-transformer for tables. Used by default.
*
* @param array $response
* @param int $iterations
* @param string $request_dimension
* @param array $custom_fields
* @return array
*/
public static function responseDataTransform(array $response, $iterations, $request_dimension, $custom_fields) {
$result = [];
$int_query = true;
$max_values = 0;
foreach ($response as $item) {
$metric_val = $item['metrics'][0]['values'];
$dimension_val = $item['dimensions'][0];
$dimension_count = count($item['dimensions']);
/** remove "0001" from dimension keys **/
for ($i = 0; $i < $dimension_count; $i++) {
$current_value = $item['dimensions'][$i];
if (ctype_digit(strval($current_value))) {
$item['dimensions'][$i] = (int)$current_value;
if ($i == 0) {
$dimension_val = (int)$current_value;
}
}
elseif ($i == 1) {
$int_query = false;
}
}
/** --------------------------------- **/
if ($dimension_count == 2) {
$dimension_val_2 = $item['dimensions'][1];
if (count($metric_val) > 1) {
for ($i = 0; $i < count($metric_val); $i++) {
$result[$dimension_val][$dimension_val_2][] = (int)$metric_val[$i];
}
} else {
$result[$dimension_val][$dimension_val_2] = (int)$metric_val[0];
}
}
else {
if (count($metric_val) > 1) {
for ($i = 0; $i < count($metric_val); $i++) {
$result[$dimension_val][] = (int)$metric_val[$i];
}
} else {
$result[$dimension_val] = (int)$metric_val[0];
}
}
$dim_val_count = count($result[$dimension_val]);
if ($dim_val_count > $max_values) $max_values = $dim_val_count;
unset($dim_val_count);
}
$int_query = self::checkDimension($request_dimension);
/** ------ filling missing data ------ **/
if ($int_query) {
foreach ($result as $key => $item) {
if (!is_array($item)) break;
$iterations = $iterations ?? $max_values;
for ($i = 0; $i < $iterations; $i++) {
$result[$key][$i] = $item[$i] ?? 0;
}
ksort($result[$key]);
}
}
/** --------------------------------- **/
/** ----- add custom fields ------ **/
foreach ($custom_fields as $key => $value) {
$result[$key] = $value ?? 'Неизвестный';
}
/** ------------------------------ **/
return $result;
}
/**
* Data-transformer for charts, when query string contains "?chart=true"
*
* @param array $data
* @return array
*/
public static function chartTransform(array $data) {
$result = [];
foreach ($data as $key => $value) {
/** Skip custom field **/
if ($key === 'name' || $key == 'id' || $key == 'view_id') {
$result[$key] = $value;
}
/** ---------------- **/
/** Remove keys and add 'data' array **/
else {
if (!is_array($value)) {
$result['data'][] = $value;
}
else {
foreach ($value as $v_key => $v_value) {
$result['data'][$key][$v_key] = $v_value;
}
ksort($result['data'][$key]);
}
}
/** ------------------------------- **/
}
return $result;
}
/**
* Deprecated
*
* @param array $data
* @return array
*/
public static function chartTransform1(array $data) {
$result = [];
$max = 0;
foreach ($data as $key => $value) {
if ($key == 'name') {
$result[$key] = $value;
continue;
}
if (!is_array($value)) break;
/** ------ check array keys for int values --- **/
$count = count($value);
if ($count > $max) $max = $count;
$int_type = true;
foreach ($value as $inc_key => $inc_value) {
if (!preg_match('/\d+/', $inc_key)) {
$int_type = false;
break;
}
}
/** ------------------------------------------ **/
/** rewrites keys like "0001" to integer type **/
if ($int_type) {
$bad_keys = array_keys($value);
for ($i = 0; $i < $count; $i++) {
$good_key = (int)$bad_keys[$i];
$result[$key][$good_key] = $value[$bad_keys[$i]] ?? 0;
}
}
/** ------------------------------------------ **/
}
/** ---------- filling missing data ---------- **/
foreach ($result as $key => $value) {
if ($key == 'name') continue;
for ($i = 0; $i < $max; $i++) {
$result[$key][$i] = (int)$result[$key][$i] ?? 0;
}
ksort($result[$key]);
}
/** ------------------------------------------ **/
return $result;
}
/**
* Deprecated
*
* @param array $response
* @param string $project_name
* @return array
*/
public static function responseChartTransform(array $response, $project_name) {
$result = [];
foreach ($response as $item) {
$result['name'] = $project_name;
$metric_val = $item['metrics'][0]['values'];
$dimension_val = $item['dimensions'][0];
$dimension_count = count($item['dimensions']);
if ($dimension_count == 2) {
$dimension_val_2 = $item['dimensions'][1];
if (count($metric_val) > 1) {
for ($i = 0; $i < count($metric_val); $i++) {
$result['data'][$dimension_val][] = (int)$metric_val[$i];
}
} else {
$result['data'][$dimension_val][] = (int)$metric_val[0];
}
}
else {
if (count($metric_val) > 1) {
for ($i = 0; $i < count($metric_val); $i++) {
$result['data'][] = (int)$metric_val[$i];
}
} else {
$result['data'][] = (int)$metric_val[0];
}
}
}
return $result;
}
/**
* Compute count of fields
*
* @param string $request_dim
* @param int $request_days
* @return int
* @throws ContentNotFound if functions params is empty
*/
public static function countIterations($request_dim, $request_days) {
if (empty($request_dim)) throw new ContentNotFound('PHP: request_dim not found', ErrorCodes::DATA_NOT_FOUND);
if (empty($request_days)) throw new ContentNotFound('PHP: request_days not found', ErrorCodes::DATA_NOT_FOUND);
switch ($request_dim) {
case 'ga:nthDay':
$iterations = $request_days*1;
break;
case 'ga:nthHour':
$iterations = $request_days*24;
break;
case 'ga:nthMinute':
$iterations = $request_days*24*60;
break;
default:
$iterations = null;
}
return $iterations;
}
/**
* Boolean indicator for chart transformer
*
* @param string $dimension
* @return bool
*/
public static function checkDimension($dimension) {
$nthArray = ['ga:nthMonth', 'ga:nthWeek', 'ga:nthDay', 'ga:nthMinute', 'ga:nthHour'];
return in_array($dimension, $nthArray) ? true : false;
}
/**
* without usage, from google docs.
*/
public function printResults($reports) {
$res = '';
for ( $reportIndex = 0; $reportIndex < count( $reports ); $reportIndex++ ) {
$report = $reports[ $reportIndex ];
$header = $report->getColumnHeader();
$dimensionHeaders = $header->getDimensions();
$metricHeaders = $header->getMetricHeader()->getMetricHeaderEntries();
$rows = $report->getData()->getRows();
for ( $rowIndex = 0; $rowIndex < count($rows); $rowIndex++) {
$row = $rows[ $rowIndex ];
$dimensions = $row->getDimensions();
$metrics = $row->getMetrics();
for ($i = 0; $i < count($dimensionHeaders) && $i < count($dimensions); $i++) {
print($dimensionHeaders[$i] . ": " . $dimensions[$i] . "\n");
}
for ($j = 0; $j < count( $metricHeaders ) && $j < count( $metrics ); $j++) {
$entry = $metricHeaders[$j];
$values = $metrics[$j];
//print("Metric type: " . $entry->getType() . "\n" );
for ( $valueIndex = 0; $valueIndex < count( $values->getValues() ); $valueIndex++ ) {
$value = $values->getValues()[ $valueIndex ];
$res .= "" . $entry->getName() . ": " . $value . '
';
}
}
}
}
return $res;
}
}