diff --git a/module/CLI/src/Command/Shortcode/GenerateShortcodeCommand.php b/module/CLI/src/Command/Shortcode/GenerateShortcodeCommand.php index 2830fb40..eaa2d634 100644 --- a/module/CLI/src/Command/Shortcode/GenerateShortcodeCommand.php +++ b/module/CLI/src/Command/Shortcode/GenerateShortcodeCommand.php @@ -9,6 +9,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; 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\Question\Question; use Zend\Diactoros\Uri; @@ -54,7 +55,13 @@ class GenerateShortcodeCommand extends Command ->setDescription( $this->translator->translate('Generates a short code for provided URL and returns the short URL') ) - ->addArgument('longUrl', InputArgument::REQUIRED, $this->translator->translate('The long URL to parse')); + ->addArgument('longUrl', InputArgument::REQUIRED, $this->translator->translate('The long URL to parse')) + ->addOption( + 'tags', + 't', + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + $this->translator->translate('Tags to apply to the new short URL') + ); } public function interact(InputInterface $input, OutputInterface $output) @@ -80,6 +87,13 @@ class GenerateShortcodeCommand extends Command public function execute(InputInterface $input, OutputInterface $output) { $longUrl = $input->getArgument('longUrl'); + $tags = $input->getOption('tags'); + $processedTags = []; + foreach ($tags as $key => $tag) { + $explodedTags = explode(',', $tag); + $processedTags = array_merge($processedTags, $explodedTags); + } + $tags = $processedTags; try { if (! isset($longUrl)) { @@ -87,10 +101,10 @@ class GenerateShortcodeCommand extends Command return; } - $shortCode = $this->urlShortener->urlToShortCode(new Uri($longUrl)); + $shortCode = $this->urlShortener->urlToShortCode(new Uri($longUrl), $tags); $shortUrl = (new Uri())->withPath($shortCode) - ->withScheme($this->domainConfig['schema']) - ->withHost($this->domainConfig['hostname']); + ->withScheme($this->domainConfig['schema']) + ->withHost($this->domainConfig['hostname']); $output->writeln([ sprintf('%s %s', $this->translator->translate('Processed URL:'), $longUrl), diff --git a/module/CLI/test/Command/Shortcode/GenerateShortcodeCommandTest.php b/module/CLI/test/Command/Shortcode/GenerateShortcodeCommandTest.php index 43367f31..e2bf9c6e 100644 --- a/module/CLI/test/Command/Shortcode/GenerateShortcodeCommandTest.php +++ b/module/CLI/test/Command/Shortcode/GenerateShortcodeCommandTest.php @@ -39,8 +39,8 @@ class GenerateShortcodeCommandTest extends TestCase */ public function properShortCodeIsCreatedIfLongUrlIsCorrect() { - $this->urlShortener->urlToShortCode(Argument::any())->willReturn('abc123') - ->shouldBeCalledTimes(1); + $this->urlShortener->urlToShortCode(Argument::cetera())->willReturn('abc123') + ->shouldBeCalledTimes(1); $this->commandTester->execute([ 'command' => 'shortcode:generate', @@ -55,8 +55,8 @@ class GenerateShortcodeCommandTest extends TestCase */ public function exceptionWhileParsingLongUrlOutputsError() { - $this->urlShortener->urlToShortCode(Argument::any())->willThrow(new InvalidUrlException()) - ->shouldBeCalledTimes(1); + $this->urlShortener->urlToShortCode(Argument::cetera())->willThrow(new InvalidUrlException()) + ->shouldBeCalledTimes(1); $this->commandTester->execute([ 'command' => 'shortcode:generate', diff --git a/module/Core/src/Service/UrlShortener.php b/module/Core/src/Service/UrlShortener.php index ed87b604..38be02f5 100644 --- a/module/Core/src/Service/UrlShortener.php +++ b/module/Core/src/Service/UrlShortener.php @@ -12,9 +12,12 @@ use Shlinkio\Shlink\Common\Exception\RuntimeException; use Shlinkio\Shlink\Core\Entity\ShortUrl; use Shlinkio\Shlink\Core\Exception\InvalidShortCodeException; use Shlinkio\Shlink\Core\Exception\InvalidUrlException; +use Shlinkio\Shlink\Core\Util\TagManagerTrait; class UrlShortener implements UrlShortenerInterface { + use TagManagerTrait; + const DEFAULT_CHARS = '123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ'; /** @@ -59,15 +62,16 @@ class UrlShortener implements UrlShortenerInterface * Creates and persists a unique shortcode generated for provided url * * @param UriInterface $url + * @param string[] $tags * @return string * @throws InvalidUrlException * @throws RuntimeException */ - public function urlToShortCode(UriInterface $url) + public function urlToShortCode(UriInterface $url, array $tags = []) { // If the url already exists in the database, just return its short code $shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([ - 'originalUrl' => $url + 'originalUrl' => $url, ]); if (isset($shortUrl)) { return $shortUrl->getShortCode(); @@ -88,7 +92,8 @@ class UrlShortener implements UrlShortenerInterface // Generate the short code and persist it $shortCode = $this->convertAutoincrementIdToShortCode($shortUrl->getId()); - $shortUrl->setShortCode($shortCode); + $shortUrl->setShortCode($shortCode) + ->setTags($this->tagNamesToEntities($this->em, $tags)); $this->em->flush(); $this->em->commit(); diff --git a/module/Core/src/Service/UrlShortenerInterface.php b/module/Core/src/Service/UrlShortenerInterface.php index 07d45401..4ddf4b7b 100644 --- a/module/Core/src/Service/UrlShortenerInterface.php +++ b/module/Core/src/Service/UrlShortenerInterface.php @@ -12,11 +12,12 @@ interface UrlShortenerInterface * Creates and persists a unique shortcode generated for provided url * * @param UriInterface $url + * @param string[] $tags * @return string * @throws InvalidUrlException * @throws RuntimeException */ - public function urlToShortCode(UriInterface $url); + public function urlToShortCode(UriInterface $url, array $tags = []); /** * Tries to find the mapped URL for provided short code. Returns null if not found diff --git a/module/Core/src/Util/TagManagerTrait.php b/module/Core/src/Util/TagManagerTrait.php new file mode 100644 index 00000000..f4dec468 --- /dev/null +++ b/module/Core/src/Util/TagManagerTrait.php @@ -0,0 +1,26 @@ +getRepository(Tag::class)->findOneBy(['name' => $tagName]) ?: (new Tag())->setName($tagName); + $em->persist($tag); + $entities[] = $tag; + } + + return new Collections\ArrayCollection($entities); + } +} diff --git a/module/Rest/src/Action/CreateShortcodeAction.php b/module/Rest/src/Action/CreateShortcodeAction.php index 5dd1221e..3f249c0d 100644 --- a/module/Rest/src/Action/CreateShortcodeAction.php +++ b/module/Rest/src/Action/CreateShortcodeAction.php @@ -16,7 +16,7 @@ use Zend\I18n\Translator\TranslatorInterface; class CreateShortcodeAction extends AbstractRestAction { /** - * @var UrlShortener|UrlShortenerInterface + * @var UrlShortenerInterface */ private $urlShortener; /** @@ -31,7 +31,7 @@ class CreateShortcodeAction extends AbstractRestAction /** * GenerateShortcodeMiddleware constructor. * - * @param UrlShortenerInterface|UrlShortener $urlShortener + * @param UrlShortenerInterface $urlShortener * @param TranslatorInterface $translator * @param array $domainConfig * @param LoggerInterface|null $logger