*/ private const METRIC_COLUMNS = [ 'ESTIMATED_EARNINGS' => 'estimated_earnings', 'PAGE_VIEWS' => 'page_views', 'PAGE_VIEWS_CTR' => 'page_views_ctr', 'PAGE_VIEWS_RPM' => 'page_views_rpm', 'AD_REQUESTS' => 'ad_requests', 'AD_REQUESTS_COVERAGE' => 'ad_requests_coverage', 'AD_REQUESTS_CTR' => 'ad_requests_ctr', 'AD_REQUESTS_RPM' => 'ad_requests_rpm', 'MATCHED_AD_REQUESTS' => 'matched_ad_requests', 'IMPRESSIONS' => 'impressions', 'IMPRESSIONS_CTR' => 'impressions_ctr', 'IMPRESSIONS_RPM' => 'impressions_rpm', 'CLICKS' => 'clicks', 'COST_PER_CLICK' => 'cost_per_click', ]; /** * @var list */ private const INTEGER_COLUMNS = [ 'page_views', 'ad_requests', 'matched_ad_requests', 'impressions', 'clicks', ]; /** * @param array $report * @return list> */ public function parse(array $report, string $dimensionType, string $accountResourceName): array { $indexByName = $this->headerIndex($report['headers'] ?? []); $currencyCode = $this->currencyCode($report['headers'] ?? []); $rows = []; foreach ($report['rows'] ?? [] as $row) { if (! is_array($row)) { continue; } $cells = $row['cells'] ?? []; if (! is_array($cells)) { continue; } $date = $this->cell($cells, $indexByName, 'DATE'); if (! is_string($date) || $date === '') { continue; } $dimensionKey = $this->dimensionKey($cells, $indexByName, $dimensionType); if ($dimensionKey === null || $dimensionKey === '') { continue; } $parsed = [ 'date' => $date, 'account_resource_name' => $accountResourceName, 'dimension_type' => $dimensionType, 'dimension_key' => $dimensionKey, 'dimension_label' => $this->dimensionLabel($cells, $indexByName, $dimensionType, $dimensionKey), 'currency_code' => $currencyCode, ]; foreach (self::METRIC_COLUMNS as $header => $column) { $parsed[$column] = $this->metricValue($cells, $indexByName, $header, $column); } $rows[] = $parsed; } return $rows; } public function currencyCode(array $headers): ?string { foreach ($headers as $header) { if (! is_array($header)) { continue; } $type = strtoupper((string) ($header['type'] ?? '')); $code = trim((string) ($header['currencyCode'] ?? '')); if ($type === 'METRIC_CURRENCY' && $code !== '') { return $code; } } return null; } /** * @return array */ private function headerIndex(mixed $headers): array { $index = []; if (! is_array($headers)) { return $index; } foreach ($headers as $position => $header) { if (! is_array($header)) { continue; } $name = strtoupper(trim((string) ($header['name'] ?? ''))); if ($name === '') { continue; } $index[$name] = (int) $position; } return $index; } /** * @param array $cells * @param array $indexByName */ private function dimensionKey(array $cells, array $indexByName, string $dimensionType): ?string { return match ($dimensionType) { AdsenseDailyStat::DIMENSION_TOTAL => AdsenseDailyStat::TOTAL_DIMENSION_KEY, AdsenseDailyStat::DIMENSION_AD_UNIT => $this->cell($cells, $indexByName, 'AD_UNIT_ID') ?? $this->cell($cells, $indexByName, 'AD_UNIT_NAME'), AdsenseDailyStat::DIMENSION_CUSTOM_CHANNEL => $this->cell($cells, $indexByName, 'CUSTOM_CHANNEL_ID') ?? $this->cell($cells, $indexByName, 'CUSTOM_CHANNEL_NAME'), AdsenseDailyStat::DIMENSION_PLATFORM => $this->cell($cells, $indexByName, 'PLATFORM_TYPE_CODE') ?? $this->cell($cells, $indexByName, 'PLATFORM_TYPE_NAME'), AdsenseDailyStat::DIMENSION_COUNTRY => $this->cell($cells, $indexByName, 'COUNTRY_CODE') ?? $this->cell($cells, $indexByName, 'COUNTRY_NAME'), default => null, }; } /** * @param array $cells * @param array $indexByName */ private function dimensionLabel(array $cells, array $indexByName, string $dimensionType, string $dimensionKey): string { $label = match ($dimensionType) { AdsenseDailyStat::DIMENSION_TOTAL => 'Total', AdsenseDailyStat::DIMENSION_AD_UNIT => $this->cell($cells, $indexByName, 'AD_UNIT_NAME'), AdsenseDailyStat::DIMENSION_CUSTOM_CHANNEL => $this->cell($cells, $indexByName, 'CUSTOM_CHANNEL_NAME'), AdsenseDailyStat::DIMENSION_PLATFORM => $this->cell($cells, $indexByName, 'PLATFORM_TYPE_NAME') ?? $this->cell($cells, $indexByName, 'PLATFORM_TYPE_CODE'), AdsenseDailyStat::DIMENSION_COUNTRY => $this->cell($cells, $indexByName, 'COUNTRY_NAME') ?? $this->cell($cells, $indexByName, 'COUNTRY_CODE'), default => $dimensionKey, }; return is_string($label) && $label !== '' ? $label : $dimensionKey; } /** * @param array $cells * @param array $indexByName */ private function cell(array $cells, array $indexByName, string $name): ?string { $name = strtoupper($name); if (! array_key_exists($name, $indexByName)) { return null; } $cell = $cells[$indexByName[$name]] ?? null; if (is_array($cell)) { $value = $cell['value'] ?? null; return is_scalar($value) ? (string) $value : null; } return is_scalar($cell) ? (string) $cell : null; } /** * @param array $cells * @param array $indexByName */ private function metricValue(array $cells, array $indexByName, string $header, string $column): int|string|null { $raw = $this->cell($cells, $indexByName, $header); if ($raw === null || $raw === '') { return null; } if (in_array($column, self::INTEGER_COLUMNS, true)) { return (int) $raw; } if (! is_numeric($raw)) { return null; } return $raw; } }