diff --git a/module/CLI/config/dependencies.config.php b/module/CLI/config/dependencies.config.php
index f9bb9654..3853fd1d 100644
--- a/module/CLI/config/dependencies.config.php
+++ b/module/CLI/config/dependencies.config.php
@@ -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,
diff --git a/module/CLI/src/Command/ShortUrl/CreateShortUrlCommand.php b/module/CLI/src/Command/ShortUrl/CreateShortUrlCommand.php
index d47c30b9..0273da71 100644
--- a/module/CLI/src/Command/ShortUrl/CreateShortUrlCommand.php
+++ b/module/CLI/src/Command/ShortUrl/CreateShortUrlCommand.php
@@ -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: %s', $longUrl),
+ sprintf('Processed long URL: %s', $result->shortUrl->getLongUrl()),
sprintf('Generated short URL: %s', $this->stringifier->stringify($result->shortUrl)),
]);
return ExitCode::EXIT_SUCCESS;
diff --git a/module/CLI/src/Command/ShortUrl/EditShortUrlCommand.php b/module/CLI/src/Command/ShortUrl/EditShortUrlCommand.php
index b3fd0bd4..048b3934 100644
--- a/module/CLI/src/Command/ShortUrl/EditShortUrlCommand.php
+++ b/module/CLI/src/Command/ShortUrl/EditShortUrlCommand.php
@@ -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;
}
}
diff --git a/module/CLI/src/Input/ShortUrlDataInput.php b/module/CLI/src/Input/ShortUrlDataInput.php
index 46c5b1ce..30121547 100644
--- a/module/CLI/src/Input/ShortUrlDataInput.php
+++ b/module/CLI/src/Input/ShortUrlDataInput.php
@@ -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'),
+ ];
+ }
}