diff --git a/module/CLI/src/Command/Domain/GetDomainVisitsCommand.php b/module/CLI/src/Command/Domain/GetDomainVisitsCommand.php
index 676a2141..8d2eb8c9 100644
--- a/module/CLI/src/Command/Domain/GetDomainVisitsCommand.php
+++ b/module/CLI/src/Command/Domain/GetDomainVisitsCommand.php
@@ -25,7 +25,7 @@ class GetDomainVisitsCommand extends AbstractVisitsListCommand
parent::__construct($visitsHelper);
}
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
diff --git a/module/CLI/src/Command/ShortUrl/GetShortUrlVisitsCommand.php b/module/CLI/src/Command/ShortUrl/GetShortUrlVisitsCommand.php
index 7f81e4da..a6a4f31d 100644
--- a/module/CLI/src/Command/ShortUrl/GetShortUrlVisitsCommand.php
+++ b/module/CLI/src/Command/ShortUrl/GetShortUrlVisitsCommand.php
@@ -20,7 +20,7 @@ class GetShortUrlVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'short-url:visits';
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php
index 0889bb03..11443abc 100644
--- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php
+++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php
@@ -4,7 +4,8 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
-use Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand;
+use Shlinkio\Shlink\CLI\Option\EndDateOption;
+use Shlinkio\Shlink\CLI\Option\StartDateOption;
use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
use Shlinkio\Shlink\Common\Paginator\Paginator;
@@ -15,6 +16,7 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlsParams;
use Shlinkio\Shlink\Core\ShortUrl\Model\TagsMode;
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlsParamsInputFilter;
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlServiceInterface;
+use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -27,20 +29,25 @@ use function Functional\map;
use function implode;
use function sprintf;
-class ListShortUrlsCommand extends AbstractWithDateRangeCommand
+class ListShortUrlsCommand extends Command
{
use PagerfantaUtilsTrait;
public const NAME = 'short-url:list';
+ private readonly StartDateOption $startDateOption;
+ private readonly EndDateOption $endDateOption;
+
public function __construct(
- private ShortUrlServiceInterface $shortUrlService,
- private DataTransformerInterface $transformer,
+ private readonly ShortUrlServiceInterface $shortUrlService,
+ private readonly DataTransformerInterface $transformer,
) {
parent::__construct();
+ $this->startDateOption = new StartDateOption($this, 'short URLs');
+ $this->endDateOption = new EndDateOption($this, 'short URLs');
}
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
@@ -104,16 +111,6 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
);
}
- protected function getStartDateDesc(string $optionName): string
- {
- return sprintf('Allows to filter short URLs, returning only those created after "%s".', $optionName);
- }
-
- protected function getEndDateDesc(string $optionName): string
- {
- return sprintf('Allows to filter short URLs, returning only those created before "%s".', $optionName);
- }
-
protected function execute(InputInterface $input, OutputInterface $output): ?int
{
$io = new SymfonyStyle($input, $output);
@@ -124,8 +121,8 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
$tagsMode = $input->getOption('including-all-tags') === true ? TagsMode::ALL->value : TagsMode::ANY->value;
$tags = ! empty($tags) ? explode(',', $tags) : [];
$all = $input->getOption('all');
- $startDate = $this->getStartDateOption($input, $output);
- $endDate = $this->getEndDateOption($input, $output);
+ $startDate = $this->startDateOption->get($input, $output);
+ $endDate = $this->endDateOption->get($input, $output);
$orderBy = $this->processOrderBy($input);
$columnsMap = $this->resolveColumnsMap($input);
diff --git a/module/CLI/src/Command/Tag/GetTagVisitsCommand.php b/module/CLI/src/Command/Tag/GetTagVisitsCommand.php
index 842c9b45..290a172a 100644
--- a/module/CLI/src/Command/Tag/GetTagVisitsCommand.php
+++ b/module/CLI/src/Command/Tag/GetTagVisitsCommand.php
@@ -25,7 +25,7 @@ class GetTagVisitsCommand extends AbstractVisitsListCommand
parent::__construct($visitsHelper);
}
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
diff --git a/module/CLI/src/Command/Util/AbstractWithDateRangeCommand.php b/module/CLI/src/Command/Util/AbstractWithDateRangeCommand.php
deleted file mode 100644
index c3e3c407..00000000
--- a/module/CLI/src/Command/Util/AbstractWithDateRangeCommand.php
+++ /dev/null
@@ -1,69 +0,0 @@
-doConfigure();
- $this
- ->addOption(self::START_DATE, 's', InputOption::VALUE_REQUIRED, $this->getStartDateDesc(self::START_DATE))
- ->addOption(self::END_DATE, 'e', InputOption::VALUE_REQUIRED, $this->getEndDateDesc(self::END_DATE));
- }
-
- protected function getStartDateOption(InputInterface $input, OutputInterface $output): ?Chronos
- {
- return $this->getDateOption($input, $output, self::START_DATE);
- }
-
- protected function getEndDateOption(InputInterface $input, OutputInterface $output): ?Chronos
- {
- return $this->getDateOption($input, $output, self::END_DATE);
- }
-
- private function getDateOption(InputInterface $input, OutputInterface $output, string $key): ?Chronos
- {
- $value = $input->getOption($key);
- if (empty($value) || ! is_string($value)) {
- return null;
- }
-
- try {
- return Chronos::parse($value);
- } catch (Throwable $e) {
- $output->writeln(sprintf(
- '> Ignored provided "%s" since its value "%s" is not a valid date. <',
- $key,
- $value,
- ));
-
- if ($output->isVeryVerbose()) {
- $this->getApplication()?->renderThrowable($e, $output);
- }
-
- return null;
- }
- }
-
- abstract protected function doConfigure(): void;
-
- abstract protected function getStartDateDesc(string $optionName): string;
-
- abstract protected function getEndDateDesc(string $optionName): string;
-}
diff --git a/module/CLI/src/Command/Visit/AbstractVisitsListCommand.php b/module/CLI/src/Command/Visit/AbstractVisitsListCommand.php
index 37a875c6..402d5ba4 100644
--- a/module/CLI/src/Command/Visit/AbstractVisitsListCommand.php
+++ b/module/CLI/src/Command/Visit/AbstractVisitsListCommand.php
@@ -4,13 +4,15 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Command\Visit;
-use Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand;
+use Shlinkio\Shlink\CLI\Option\EndDateOption;
+use Shlinkio\Shlink\CLI\Option\StartDateOption;
use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
use Shlinkio\Shlink\Common\Paginator\Paginator;
use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
+use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@@ -19,29 +21,23 @@ use function Functional\map;
use function Functional\select_keys;
use function Shlinkio\Shlink\Common\buildDateRange;
use function Shlinkio\Shlink\Core\camelCaseToHumanFriendly;
-use function sprintf;
-abstract class AbstractVisitsListCommand extends AbstractWithDateRangeCommand
+abstract class AbstractVisitsListCommand extends Command
{
+ private readonly StartDateOption $startDateOption;
+ private readonly EndDateOption $endDateOption;
+
public function __construct(protected readonly VisitsStatsHelperInterface $visitsHelper)
{
parent::__construct();
- }
-
- final protected function getStartDateDesc(string $optionName): string
- {
- return sprintf('Allows to filter visits, returning only those older than "%s".', $optionName);
- }
-
- final protected function getEndDateDesc(string $optionName): string
- {
- return sprintf('Allows to filter visits, returning only those newer than "%s".', $optionName);
+ $this->startDateOption = new StartDateOption($this, 'visits');
+ $this->endDateOption = new EndDateOption($this, 'visits');
}
final protected function execute(InputInterface $input, OutputInterface $output): ?int
{
- $startDate = $this->getStartDateOption($input, $output);
- $endDate = $this->getEndDateOption($input, $output);
+ $startDate = $this->startDateOption->get($input, $output);
+ $endDate = $this->endDateOption->get($input, $output);
$paginator = $this->getVisitsPaginator($input, buildDateRange($startDate, $endDate));
[$rows, $headers] = $this->resolveRowsAndHeaders($paginator);
diff --git a/module/CLI/src/Command/Visit/GetNonOrphanVisitsCommand.php b/module/CLI/src/Command/Visit/GetNonOrphanVisitsCommand.php
index 0b4a4612..0dd32f3e 100644
--- a/module/CLI/src/Command/Visit/GetNonOrphanVisitsCommand.php
+++ b/module/CLI/src/Command/Visit/GetNonOrphanVisitsCommand.php
@@ -23,7 +23,7 @@ class GetNonOrphanVisitsCommand extends AbstractVisitsListCommand
parent::__construct($visitsHelper);
}
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
diff --git a/module/CLI/src/Command/Visit/GetOrphanVisitsCommand.php b/module/CLI/src/Command/Visit/GetOrphanVisitsCommand.php
index c2d353af..618a35cd 100644
--- a/module/CLI/src/Command/Visit/GetOrphanVisitsCommand.php
+++ b/module/CLI/src/Command/Visit/GetOrphanVisitsCommand.php
@@ -14,7 +14,7 @@ class GetOrphanVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'visit:orphan';
- protected function doConfigure(): void
+ protected function configure(): void
{
$this
->setName(self::NAME)
diff --git a/module/CLI/src/Option/DateOption.php b/module/CLI/src/Option/DateOption.php
new file mode 100644
index 00000000..a863696f
--- /dev/null
+++ b/module/CLI/src/Option/DateOption.php
@@ -0,0 +1,51 @@
+addOption($name, $shortcut, InputOption::VALUE_REQUIRED, $description);
+ }
+
+ public function get(InputInterface $input, OutputInterface $output): ?Chronos
+ {
+ $value = $input->getOption($this->name);
+ if (empty($value) || ! is_string($value)) {
+ return null;
+ }
+
+ try {
+ return Chronos::parse($value);
+ } catch (Throwable $e) {
+ $output->writeln(sprintf(
+ '> Ignored provided "%s" since its value "%s" is not a valid date. <',
+ $this->name,
+ $value,
+ ));
+
+ if ($output->isVeryVerbose()) {
+ $this->command->getApplication()?->renderThrowable($e, $output);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/module/CLI/src/Option/EndDateOption.php b/module/CLI/src/Option/EndDateOption.php
new file mode 100644
index 00000000..72421981
--- /dev/null
+++ b/module/CLI/src/Option/EndDateOption.php
@@ -0,0 +1,30 @@
+dateOption = new DateOption($command, 'end-date', 'e', sprintf(
+ 'Allows to filter %s, returning only those newer than provided date.',
+ $descriptionHint,
+ ));
+ }
+
+ public function get(InputInterface $input, OutputInterface $output): ?Chronos
+ {
+ return $this->dateOption->get($input, $output);
+ }
+}
diff --git a/module/CLI/src/Option/StartDateOption.php b/module/CLI/src/Option/StartDateOption.php
new file mode 100644
index 00000000..2da5aaee
--- /dev/null
+++ b/module/CLI/src/Option/StartDateOption.php
@@ -0,0 +1,30 @@
+dateOption = new DateOption($command, 'start-date', 's', sprintf(
+ 'Allows to filter %s, returning only those older than provided date.',
+ $descriptionHint,
+ ));
+ }
+
+ public function get(InputInterface $input, OutputInterface $output): ?Chronos
+ {
+ return $this->dateOption->get($input, $output);
+ }
+}