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; } }