matomoEnabled = $matomoOptions->enabled; parent::__construct(); } protected function configure(): void { $help = <<%command.name% Send all visits created before 2024: %command.name% --until 2023-12-31 Send all visits created after a specific day: %command.name% --since 2022-03-27 Send all visits created during 2022: %command.name% --since 2022-01-01 --until 2022-12-31 HELP; $this ->setName(self::NAME) ->setDescription(sprintf( '%sSend existing visits to the configured matomo instance', $this->matomoEnabled ? '' : '[MATOMO INTEGRATION DISABLED] ', )) ->setHelp($help) ->addOption( 'since', 's', InputOption::VALUE_REQUIRED, 'Only visits created since this date, inclusively, will be sent to Matomo', ) ->addOption( 'until', 'u', InputOption::VALUE_REQUIRED, 'Only visits created until this date, inclusively, will be sent to Matomo', ); } protected function execute(InputInterface $input, OutputInterface $output): int { $this->io = new SymfonyStyle($input, $output); if (! $this->matomoEnabled) { $this->io->warning('Matomo integration is not enabled in this Shlink instance'); return self::INVALID; } // TODO Validate provided date formats $since = $input->getOption('since'); $until = $input->getOption('until'); $dateRange = buildDateRange( startDate: $since !== null ? Chronos::parse($since) : null, endDate: $until !== null ? Chronos::parse($until) : null, ); if ($input->isInteractive()) { $this->io->warning([ 'You are about to send visits from this Shlink instance to Matomo', 'Resolved date range -> ' . dateRangeToHumanFriendly($dateRange), 'Shlink will not check for already sent visits, which could result in some duplications. Make sure ' . 'you have verified only visits in the right date range are going to be sent.', ]); if (! $this->io->confirm('Continue?', default: false)) { return self::INVALID; } } $result = $this->visitSender->sendVisitsInDateRange($dateRange, $this); match (true) { $result->hasFailures() && $result->hasSuccesses() => $this->io->warning( sprintf('%s visits sent to Matomo. %s failed.', $result->successfulVisits, $result->failedVisits), ), $result->hasFailures() => $this->io->error( sprintf('Failed to send %s visits to Matomo.', $result->failedVisits), ), $result->hasSuccesses() => $this->io->success( sprintf('%s visits sent to Matomo.', $result->successfulVisits), ), default => $this->io->info('There was no visits matching provided date range.'), }; return self::SUCCESS; } public function success(int $index): void { $this->io->write('.'); } public function error(int $index, Throwable $e): void { $this->io->write('E'); if ($this->io->isVerbose()) { $this->getApplication()?->renderThrowable($e, $this->io); } } }