mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-27 08:18:24 +03:00
Extract reading and parsing of arguments for short URLs data in commands
This commit is contained in:
parent
38d8086516
commit
fabc752398
3 changed files with 128 additions and 66 deletions
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Input\ShortUrlDataInput;
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
|
@ -12,16 +13,11 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
|
|||
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\UrlShortenerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function array_map;
|
||||
use function array_unique;
|
||||
use function explode;
|
||||
use function Shlinkio\Shlink\Core\ArrayUtils\flatten;
|
||||
use function sprintf;
|
||||
|
||||
class CreateShortUrlCommand extends Command
|
||||
|
@ -29,6 +25,7 @@ class CreateShortUrlCommand extends Command
|
|||
public const NAME = 'short-url:create';
|
||||
|
||||
private ?SymfonyStyle $io;
|
||||
private readonly ShortUrlDataInput $shortUrlDataInput;
|
||||
|
||||
public function __construct(
|
||||
private readonly UrlShortenerInterface $urlShortener,
|
||||
|
@ -36,6 +33,7 @@ class CreateShortUrlCommand extends Command
|
|||
private readonly UrlShortenerOptions $options,
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->shortUrlDataInput = new ShortUrlDataInput($this);
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
|
@ -43,26 +41,11 @@ class CreateShortUrlCommand extends Command
|
|||
$this
|
||||
->setName(self::NAME)
|
||||
->setDescription('Generates a short URL for provided long URL and returns it')
|
||||
->addArgument('longUrl', InputArgument::REQUIRED, 'The long URL to parse')
|
||||
->addOption(
|
||||
'tags',
|
||||
't',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Tags to apply to the new short URL',
|
||||
)
|
||||
->addOption(
|
||||
'valid-since',
|
||||
's',
|
||||
'domain',
|
||||
'd',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The date from which this short URL will be valid. '
|
||||
. 'If someone tries to access it before this date, it will not be found.',
|
||||
)
|
||||
->addOption(
|
||||
'valid-until',
|
||||
'u',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The date until which this short URL will be valid. '
|
||||
. 'If someone tries to access it after this date, it will not be found.',
|
||||
'The domain to which this short URL will be attached.',
|
||||
)
|
||||
->addOption(
|
||||
'custom-slug',
|
||||
|
@ -70,30 +53,6 @@ class CreateShortUrlCommand extends Command
|
|||
InputOption::VALUE_REQUIRED,
|
||||
'If provided, this slug will be used instead of generating a short code',
|
||||
)
|
||||
->addOption(
|
||||
'path-prefix',
|
||||
'p',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Prefix to prepend before the generated short code or provided custom slug',
|
||||
)
|
||||
->addOption(
|
||||
'max-visits',
|
||||
'm',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'This will limit the number of visits for this short URL.',
|
||||
)
|
||||
->addOption(
|
||||
'find-if-exists',
|
||||
'f',
|
||||
InputOption::VALUE_NONE,
|
||||
'This will force existing matching URL to be returned if found, instead of creating a new one.',
|
||||
)
|
||||
->addOption(
|
||||
'domain',
|
||||
'd',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The domain to which this short URL will be attached.',
|
||||
)
|
||||
->addOption(
|
||||
'short-code-length',
|
||||
'l',
|
||||
|
@ -101,16 +60,16 @@ class CreateShortUrlCommand extends Command
|
|||
'The length for generated short code (it will be ignored if --custom-slug was provided).',
|
||||
)
|
||||
->addOption(
|
||||
'crawlable',
|
||||
'r',
|
||||
InputOption::VALUE_NONE,
|
||||
'Tells if this URL will be included as "Allow" in Shlink\'s robots.txt.',
|
||||
'path-prefix',
|
||||
'p',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Prefix to prepend before the generated short code or provided custom slug',
|
||||
)
|
||||
->addOption(
|
||||
'no-forward-query',
|
||||
'w',
|
||||
'find-if-exists',
|
||||
'f',
|
||||
InputOption::VALUE_NONE,
|
||||
'Disables the forwarding of the query string to the long URL, when the new short URL is visited.',
|
||||
'This will force existing matching URL to be returned if found, instead of creating a new one.',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -136,31 +95,28 @@ class CreateShortUrlCommand extends Command
|
|||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = $this->getIO($input, $output);
|
||||
$longUrl = $input->getArgument('longUrl');
|
||||
$longUrl = $this->shortUrlDataInput->longUrl($input);
|
||||
if (empty($longUrl)) {
|
||||
$io->error('A URL was not provided!');
|
||||
return ExitCode::EXIT_FAILURE;
|
||||
}
|
||||
|
||||
$explodeWithComma = static fn (string $tag) => explode(',', $tag);
|
||||
$tags = array_unique(flatten(array_map($explodeWithComma, $input->getOption('tags'))));
|
||||
$maxVisits = $input->getOption('max-visits');
|
||||
$shortCodeLength = $input->getOption('short-code-length') ?? $this->options->defaultShortCodesLength;
|
||||
|
||||
try {
|
||||
$result = $this->urlShortener->shorten(ShortUrlCreation::fromRawData([
|
||||
ShortUrlInputFilter::LONG_URL => $longUrl,
|
||||
ShortUrlInputFilter::VALID_SINCE => $input->getOption('valid-since'),
|
||||
ShortUrlInputFilter::VALID_UNTIL => $input->getOption('valid-until'),
|
||||
ShortUrlInputFilter::MAX_VISITS => $maxVisits !== null ? (int) $maxVisits : null,
|
||||
ShortUrlInputFilter::VALID_SINCE => $this->shortUrlDataInput->validSince($input),
|
||||
ShortUrlInputFilter::VALID_UNTIL => $this->shortUrlDataInput->validUntil($input),
|
||||
ShortUrlInputFilter::MAX_VISITS => $this->shortUrlDataInput->maxVisits($input),
|
||||
ShortUrlInputFilter::CUSTOM_SLUG => $input->getOption('custom-slug'),
|
||||
ShortUrlInputFilter::PATH_PREFIX => $input->getOption('path-prefix'),
|
||||
ShortUrlInputFilter::FIND_IF_EXISTS => $input->getOption('find-if-exists'),
|
||||
ShortUrlInputFilter::DOMAIN => $input->getOption('domain'),
|
||||
ShortUrlInputFilter::SHORT_CODE_LENGTH => $shortCodeLength,
|
||||
ShortUrlInputFilter::TAGS => $tags,
|
||||
ShortUrlInputFilter::CRAWLABLE => $input->getOption('crawlable'),
|
||||
ShortUrlInputFilter::FORWARD_QUERY => !$input->getOption('no-forward-query'),
|
||||
ShortUrlInputFilter::TAGS => $this->shortUrlDataInput->tags($input),
|
||||
ShortUrlInputFilter::CRAWLABLE => $this->shortUrlDataInput->crawlable($input),
|
||||
ShortUrlInputFilter::FORWARD_QUERY => !$this->shortUrlDataInput->noForwardQuery($input),
|
||||
], $this->options));
|
||||
|
||||
$result->onEventDispatchingError(static fn () => $io->isVerbose() && $io->warning(
|
||||
|
|
106
module/CLI/src/Input/ShortUrlDataInput.php
Normal file
106
module/CLI/src/Input/ShortUrlDataInput.php
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Input;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function array_map;
|
||||
use function array_unique;
|
||||
use function Shlinkio\Shlink\Core\ArrayUtils\flatten;
|
||||
use function Shlinkio\Shlink\Core\splitByComma;
|
||||
|
||||
readonly final class ShortUrlDataInput
|
||||
{
|
||||
public function __construct(Command $command, private bool $longUrlAsOption = false)
|
||||
{
|
||||
if ($longUrlAsOption) {
|
||||
$command->addOption('long-url', 'l', InputOption::VALUE_REQUIRED, 'The long URL to set');
|
||||
} else {
|
||||
$command->addArgument('longUrl', InputArgument::REQUIRED, 'The long URL to set');
|
||||
}
|
||||
|
||||
$command
|
||||
->addOption(
|
||||
'tags',
|
||||
't',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Tags to apply to the short URL',
|
||||
)
|
||||
->addOption(
|
||||
'valid-since',
|
||||
's',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The date from which this short URL will be valid. '
|
||||
. 'If someone tries to access it before this date, it will not be found.',
|
||||
)
|
||||
->addOption(
|
||||
'valid-until',
|
||||
'u',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The date until which this short URL will be valid. '
|
||||
. 'If someone tries to access it after this date, it will not be found.',
|
||||
)
|
||||
->addOption(
|
||||
'max-visits',
|
||||
'm',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'This will limit the number of visits for this short URL.',
|
||||
)
|
||||
->addOption(
|
||||
'crawlable',
|
||||
'r',
|
||||
InputOption::VALUE_NONE,
|
||||
'Tells if this short URL will be included as "Allow" in Shlink\'s robots.txt.',
|
||||
)
|
||||
->addOption(
|
||||
'no-forward-query',
|
||||
'w',
|
||||
InputOption::VALUE_NONE,
|
||||
'Disables the forwarding of the query string to the long URL, when the short URL is visited.',
|
||||
);
|
||||
}
|
||||
|
||||
public function longUrl(InputInterface $input): ?string
|
||||
{
|
||||
return $this->longUrlAsOption ? $input->getOption('long-url') : $input->getArgument('longUrl');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function tags(InputInterface $input): array
|
||||
{
|
||||
return array_unique(flatten(array_map(splitByComma(...), $input->getOption('tags'))));
|
||||
}
|
||||
|
||||
public function validSince(InputInterface $input): ?string
|
||||
{
|
||||
return $input->getOption('valid-since');
|
||||
}
|
||||
|
||||
public function validUntil(InputInterface $input): ?string
|
||||
{
|
||||
return $input->getOption('valid-until');
|
||||
}
|
||||
|
||||
public function maxVisits(InputInterface $input): ?int
|
||||
{
|
||||
$maxVisits = $input->getOption('max-visits');
|
||||
return $maxVisits !== null ? (int) $maxVisits : null;
|
||||
}
|
||||
|
||||
public function crawlable(InputInterface $input): bool
|
||||
{
|
||||
return $input->getOption('crawlable');
|
||||
}
|
||||
|
||||
public function noForwardQuery(InputInterface $input): bool
|
||||
{
|
||||
return $input->getOption('no-forward-query');
|
||||
}
|
||||
}
|
|
@ -20,8 +20,8 @@ class EditShortUrlAction extends AbstractRestAction
|
|||
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH];
|
||||
|
||||
public function __construct(
|
||||
private ShortUrlServiceInterface $shortUrlService,
|
||||
private DataTransformerInterface $transformer,
|
||||
private readonly ShortUrlServiceInterface $shortUrlService,
|
||||
private readonly DataTransformerInterface $transformer,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue