mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-23 13:23:33 +03:00
Create command to edit existing short URLs
This commit is contained in:
parent
8917ed5c2e
commit
5bccdded8a
4 changed files with 73 additions and 82 deletions
|
@ -93,7 +93,7 @@ return [
|
|||
ShortUrlStringifier::class,
|
||||
UrlShortenerOptions::class,
|
||||
],
|
||||
Command\ShortUrl\EditShortUrlCommand::class => [ShortUrl\ShortUrlService::class],
|
||||
Command\ShortUrl\EditShortUrlCommand::class => [ShortUrl\ShortUrlService::class, ShortUrlStringifier::class],
|
||||
Command\ShortUrl\ResolveUrlCommand::class => [ShortUrl\ShortUrlResolver::class],
|
||||
Command\ShortUrl\ListShortUrlsCommand::class => [
|
||||
ShortUrl\ShortUrlListService::class,
|
||||
|
|
|
@ -9,8 +9,6 @@ use Shlinkio\Shlink\CLI\Util\ExitCode;
|
|||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||
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\InputInterface;
|
||||
|
@ -95,29 +93,17 @@ class CreateShortUrlCommand extends Command
|
|||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = $this->getIO($input, $output);
|
||||
$longUrl = $this->shortUrlDataInput->longUrl($input);
|
||||
if (empty($longUrl)) {
|
||||
$io->error('A URL was not provided!');
|
||||
return ExitCode::EXIT_FAILURE;
|
||||
}
|
||||
|
||||
$shortCodeLength = $input->getOption('short-code-length') ?? $this->options->defaultShortCodesLength;
|
||||
|
||||
try {
|
||||
$result = $this->urlShortener->shorten(ShortUrlCreation::fromRawData([
|
||||
ShortUrlInputFilter::LONG_URL => $longUrl,
|
||||
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 => $this->shortUrlDataInput->tags($input),
|
||||
ShortUrlInputFilter::CRAWLABLE => $this->shortUrlDataInput->crawlable($input),
|
||||
ShortUrlInputFilter::FORWARD_QUERY => !$this->shortUrlDataInput->noForwardQuery($input),
|
||||
], $this->options));
|
||||
$result = $this->urlShortener->shorten($this->shortUrlDataInput->toShortUrlCreation(
|
||||
$input,
|
||||
$this->options,
|
||||
customSlugField: 'custom-slug',
|
||||
shortCodeLengthField: 'short-code-length',
|
||||
pathPrefixField: 'path-prefix',
|
||||
findIfExistsField: 'find-if-exists',
|
||||
domainField: 'domain',
|
||||
));
|
||||
|
||||
$result->onEventDispatchingError(static fn () => $io->isVerbose() && $io->warning(
|
||||
'Short URL properly created, but the real-time updates cannot be notified when generating the '
|
||||
|
@ -125,7 +111,7 @@ class CreateShortUrlCommand extends Command
|
|||
));
|
||||
|
||||
$io->writeln([
|
||||
sprintf('Processed long URL: <info>%s</info>', $longUrl),
|
||||
sprintf('Processed long URL: <info>%s</info>', $result->shortUrl->getLongUrl()),
|
||||
sprintf('Generated short URL: <info>%s</info>', $this->stringifier->stringify($result->shortUrl)),
|
||||
]);
|
||||
return ExitCode::EXIT_SUCCESS;
|
||||
|
|
|
@ -8,12 +8,15 @@ use Shlinkio\Shlink\CLI\Input\ShortUrlDataInput;
|
|||
use Shlinkio\Shlink\CLI\Input\ShortUrlIdentifierInput;
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlServiceInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class EditShortUrlCommand extends Command
|
||||
{
|
||||
public const NAME = 'short-url:edit';
|
||||
|
@ -21,8 +24,10 @@ class EditShortUrlCommand extends Command
|
|||
private readonly ShortUrlDataInput $shortUrlDataInput;
|
||||
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;
|
||||
|
||||
public function __construct(private readonly ShortUrlServiceInterface $shortUrlService)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ShortUrlServiceInterface $shortUrlService,
|
||||
private readonly ShortUrlStringifierInterface $stringifier,
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->shortUrlDataInput = new ShortUrlDataInput($this, longUrlAsOption: true);
|
||||
|
@ -43,17 +48,23 @@ class EditShortUrlCommand extends Command
|
|||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$identifier = $this->shortUrlIdentifierInput->toShortUrlIdentifier($input);
|
||||
|
||||
try {
|
||||
$shortUrl = $this->shortUrlService->updateShortUrl(
|
||||
$this->shortUrlIdentifierInput->toShortUrlIdentifier($input),
|
||||
$identifier,
|
||||
$this->shortUrlDataInput->toShortUrlEdition($input),
|
||||
);
|
||||
|
||||
// TODO Print success
|
||||
$io->success(sprintf('Short URL "%s" properly edited', $this->stringifier->stringify($shortUrl)));
|
||||
return ExitCode::EXIT_SUCCESS;
|
||||
} catch (ShortUrlNotFoundException) {
|
||||
// TODO Print error
|
||||
} catch (ShortUrlNotFoundException $e) {
|
||||
$io->error(sprintf('Short URL not found for "%s"', $identifier->__toString()));
|
||||
|
||||
if ($io->isVerbose()) {
|
||||
$this->getApplication()?->renderThrowable($e, $io);
|
||||
}
|
||||
|
||||
return ExitCode::EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shlinkio\Shlink\CLI\Input;
|
||||
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlEdition;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
@ -53,6 +55,11 @@ readonly final class ShortUrlDataInput
|
|||
InputOption::VALUE_REQUIRED,
|
||||
'This will limit the number of visits for this short URL.',
|
||||
)
|
||||
->addOption(
|
||||
'title',
|
||||
mode: InputOption::VALUE_REQUIRED,
|
||||
description: 'A descriptive title for the short URL.',
|
||||
)
|
||||
->addOption(
|
||||
'crawlable',
|
||||
'r',
|
||||
|
@ -67,59 +74,46 @@ readonly final class ShortUrlDataInput
|
|||
);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
public function toShortUrlEdition(InputInterface $input): ShortUrlEdition
|
||||
{
|
||||
return ShortUrlEdition::fromRawData([
|
||||
ShortUrlInputFilter::LONG_URL => $this->longUrl($input),
|
||||
ShortUrlInputFilter::VALID_SINCE => $this->validSince($input),
|
||||
ShortUrlInputFilter::VALID_UNTIL => $this->validUntil($input),
|
||||
ShortUrlInputFilter::MAX_VISITS => $this->maxVisits($input),
|
||||
ShortUrlInputFilter::TAGS => $this->tags($input),
|
||||
ShortUrlInputFilter::CRAWLABLE => $this->crawlable($input),
|
||||
ShortUrlInputFilter::FORWARD_QUERY => !$this->noForwardQuery($input),
|
||||
// ShortUrlInputFilter::TITLE => TODO,
|
||||
]);
|
||||
return ShortUrlEdition::fromRawData($this->getCommonData($input));
|
||||
}
|
||||
|
||||
// TODO
|
||||
// public function toShortUrlCreation(InputInterface $input)
|
||||
public function toShortUrlCreation(
|
||||
InputInterface $input,
|
||||
UrlShortenerOptions $options,
|
||||
string $customSlugField,
|
||||
string $shortCodeLengthField,
|
||||
string $pathPrefixField,
|
||||
string $findIfExistsField,
|
||||
string $domainField,
|
||||
): ShortUrlCreation {
|
||||
$shortCodeLength = $input->getOption($shortCodeLengthField) ?? $options->defaultShortCodesLength;
|
||||
return ShortUrlCreation::fromRawData([
|
||||
...$this->getCommonData($input),
|
||||
ShortUrlInputFilter::CUSTOM_SLUG => $input->getOption($customSlugField),
|
||||
ShortUrlInputFilter::SHORT_CODE_LENGTH => $shortCodeLength,
|
||||
ShortUrlInputFilter::PATH_PREFIX => $input->getOption($pathPrefixField),
|
||||
ShortUrlInputFilter::FIND_IF_EXISTS => $input->getOption($findIfExistsField),
|
||||
ShortUrlInputFilter::DOMAIN => $input->getOption($domainField),
|
||||
], $options);
|
||||
}
|
||||
|
||||
private function getCommonData(InputInterface $input): array
|
||||
{
|
||||
$longUrl = $this->longUrlAsOption ? $input->getOption('long-url') : $input->getArgument('longUrl');
|
||||
$tags = array_unique(flatten(array_map(splitByComma(...), $input->getOption('tags'))));
|
||||
$maxVisits = $input->getOption('max-visits');
|
||||
|
||||
return [
|
||||
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::TAGS => $tags,
|
||||
ShortUrlInputFilter::TITLE => $input->getOption('title'),
|
||||
ShortUrlInputFilter::CRAWLABLE => $input->getOption('crawlable'),
|
||||
ShortUrlInputFilter::FORWARD_QUERY => !$input->getOption('no-forward-query'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue