option('force')) { $this->warn('AdSense synchronization is disabled. Use --force to run anyway.'); return self::SUCCESS; } try { [$from, $to] = $this->resolveRange(); } catch (\InvalidArgumentException $exception) { $this->error($exception->getMessage()); return self::INVALID; } $connection = AdsenseConnection::current(); if ($connection === null || ! $connection->hasRefreshToken()) { $this->error('Google AdSense is not connected.'); return self::FAILURE; } if ($connection->status === AdsenseConnection::STATUS_RECONNECT_REQUIRED) { $this->error('AdSense authorization expired or was revoked. Reconnect Google AdSense.'); return self::FAILURE; } if ((string) $connection->account_resource_name === '') { $this->error('No AdSense account is selected.'); return self::FAILURE; } $entitiesOnly = (bool) $this->option('entities-only'); $result = $sync->sync($connection, $from, $to, $entitiesOnly); $this->renderResult($result, $entitiesOnly); if ($result->reconnectRequired) { $this->error('AdSense authorization expired or was revoked. Reconnect Google AdSense.'); return self::FAILURE; } if ($result->failedReports !== []) { $this->warn('Synchronization completed with partial report failures: '.implode(', ', $result->failedReports)); return self::SUCCESS; } $this->info('Synchronization completed successfully.'); return self::SUCCESS; } /** * @return array{0: Carbon, 1: Carbon} */ private function resolveRange(): array { $days = $this->option('days'); $from = $this->option('from'); $to = $this->option('to'); if ($days !== null && ($from !== null || $to !== null)) { throw new \InvalidArgumentException('The --days option cannot be combined with --from or --to.'); } if (($from !== null) !== ($to !== null)) { throw new \InvalidArgumentException('Both --from and --to are required for a custom range.'); } if (is_string($from) && is_string($to)) { $start = Carbon::parse($from)->startOfDay(); $end = Carbon::parse($to)->startOfDay(); if ($end->lt($start)) { throw new \InvalidArgumentException('The --to date must be on or after --from.'); } return [$start, $end]; } $trailingDays = $days !== null ? max(1, (int) $days) : 3; $end = now()->startOfDay(); $start = $end->copy()->subDays($trailingDays - 1); return [$start, $end]; } private function renderResult(AdsenseSyncResult $result, bool $entitiesOnly): void { $this->line('AdSense account: '.($result->accountDisplayName !== '' ? $result->accountDisplayName : 'unknown')); $this->line('Range: '.$result->from.' -> '.$result->to); $this->newLine(); $this->line('Entities:'); $this->line(' Ad units: '.$result->adUnits); $this->line(' Custom channels: '.$result->customChannels); if ($entitiesOnly) { return; } $this->newLine(); $this->line('Reports:'); $this->line(' Total: '.$result->totalRows); $this->line(' Ad units: '.$result->adUnitRows); $this->line(' Custom channels: '.$result->customChannelRows); $this->line(' Platform: '.$result->platformRows); $this->line(' Countries: '.$result->countryRows); $this->newLine(); } }