GenerateShortUrlCommand.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. <?php
  2. declare(strict_types=1);
  3. namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
  4. use Laminas\Diactoros\Uri;
  5. use Shlinkio\Shlink\CLI\Util\ExitCodes;
  6. use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
  7. use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
  8. use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
  9. use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
  10. use Symfony\Component\Console\Command\Command;
  11. use Symfony\Component\Console\Input\InputArgument;
  12. use Symfony\Component\Console\Input\InputInterface;
  13. use Symfony\Component\Console\Input\InputOption;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15. use Symfony\Component\Console\Style\SymfonyStyle;
  16. use function array_map;
  17. use function Functional\curry;
  18. use function Functional\flatten;
  19. use function Functional\unique;
  20. use function sprintf;
  21. class GenerateShortUrlCommand extends Command
  22. {
  23. public const NAME = 'short-url:generate';
  24. private UrlShortenerInterface $urlShortener;
  25. private array $domainConfig;
  26. public function __construct(UrlShortenerInterface $urlShortener, array $domainConfig)
  27. {
  28. parent::__construct();
  29. $this->urlShortener = $urlShortener;
  30. $this->domainConfig = $domainConfig;
  31. }
  32. protected function configure(): void
  33. {
  34. $this
  35. ->setName(self::NAME)
  36. ->setDescription('Generates a short URL for provided long URL and returns it')
  37. ->addArgument('longUrl', InputArgument::REQUIRED, 'The long URL to parse')
  38. ->addOption(
  39. 'tags',
  40. 't',
  41. InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
  42. 'Tags to apply to the new short URL',
  43. )
  44. ->addOption(
  45. 'validSince',
  46. 's',
  47. InputOption::VALUE_REQUIRED,
  48. 'The date from which this short URL will be valid. '
  49. . 'If someone tries to access it before this date, it will not be found.',
  50. )
  51. ->addOption(
  52. 'validUntil',
  53. 'u',
  54. InputOption::VALUE_REQUIRED,
  55. 'The date until which this short URL will be valid. '
  56. . 'If someone tries to access it after this date, it will not be found.',
  57. )
  58. ->addOption(
  59. 'customSlug',
  60. 'c',
  61. InputOption::VALUE_REQUIRED,
  62. 'If provided, this slug will be used instead of generating a short code',
  63. )
  64. ->addOption(
  65. 'maxVisits',
  66. 'm',
  67. InputOption::VALUE_REQUIRED,
  68. 'This will limit the number of visits for this short URL.',
  69. )
  70. ->addOption(
  71. 'findIfExists',
  72. 'f',
  73. InputOption::VALUE_NONE,
  74. 'This will force existing matching URL to be returned if found, instead of creating a new one.',
  75. )
  76. ->addOption(
  77. 'domain',
  78. 'd',
  79. InputOption::VALUE_REQUIRED,
  80. 'The domain to which this short URL will be attached.',
  81. );
  82. }
  83. protected function interact(InputInterface $input, OutputInterface $output): void
  84. {
  85. $io = new SymfonyStyle($input, $output);
  86. $longUrl = $input->getArgument('longUrl');
  87. if (! empty($longUrl)) {
  88. return;
  89. }
  90. $longUrl = $io->ask('Which URL do you want to shorten?');
  91. if (! empty($longUrl)) {
  92. $input->setArgument('longUrl', $longUrl);
  93. }
  94. }
  95. protected function execute(InputInterface $input, OutputInterface $output): ?int
  96. {
  97. $io = new SymfonyStyle($input, $output);
  98. $longUrl = $input->getArgument('longUrl');
  99. if (empty($longUrl)) {
  100. $io->error('A URL was not provided!');
  101. return ExitCodes::EXIT_FAILURE;
  102. }
  103. $explodeWithComma = curry('explode')(',');
  104. $tags = unique(flatten(array_map($explodeWithComma, $input->getOption('tags'))));
  105. $customSlug = $input->getOption('customSlug');
  106. $maxVisits = $input->getOption('maxVisits');
  107. try {
  108. $shortUrl = $this->urlShortener->urlToShortCode(
  109. new Uri($longUrl),
  110. $tags,
  111. ShortUrlMeta::createFromParams(
  112. $input->getOption('validSince'),
  113. $input->getOption('validUntil'),
  114. $customSlug,
  115. $maxVisits !== null ? (int) $maxVisits : null,
  116. $input->getOption('findIfExists'),
  117. $input->getOption('domain'),
  118. ),
  119. );
  120. $io->writeln([
  121. sprintf('Processed long URL: <info>%s</info>', $longUrl),
  122. sprintf('Generated short URL: <info>%s</info>', $shortUrl->toString($this->domainConfig)),
  123. ]);
  124. return ExitCodes::EXIT_SUCCESS;
  125. } catch (InvalidUrlException | NonUniqueSlugException $e) {
  126. $io->error($e->getMessage());
  127. return ExitCodes::EXIT_FAILURE;
  128. }
  129. }
  130. }