Completed
Pull Request — master (#199)
by Alejandro
02:49
created

GenerateShortcodeCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 30
ccs 20
cts 20
cp 1
crap 1
rs 9.44
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\CLI\Command\Shortcode;
5
6
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
7
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
8
use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
9
use Shlinkio\Shlink\Core\Util\ShortUrlBuilderTrait;
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 Zend\Diactoros\Uri;
17
use Zend\I18n\Translator\TranslatorInterface;
18
19
class GenerateShortcodeCommand extends Command
20
{
21
    use ShortUrlBuilderTrait;
22
23
    public const NAME = 'short-code:generate';
24
    private const ALIASES = ['shortcode:generate'];
25
26
    /**
27
     * @var UrlShortenerInterface
28
     */
29
    private $urlShortener;
30
    /**
31
     * @var array
32
     */
33
    private $domainConfig;
34
    /**
35
     * @var TranslatorInterface
36
     */
37
    private $translator;
38
39 2
    public function __construct(
40
        UrlShortenerInterface $urlShortener,
41
        TranslatorInterface $translator,
42
        array $domainConfig
43
    ) {
44 2
        $this->urlShortener = $urlShortener;
45 2
        $this->translator = $translator;
46 2
        $this->domainConfig = $domainConfig;
47 2
        parent::__construct(null);
48 2
    }
49
50 2
    protected function configure(): void
51
    {
52
        $this
53 2
            ->setName(self::NAME)
54 2
            ->setAliases(self::ALIASES)
55 2
            ->setDescription(
56 2
                $this->translator->translate('Generates a short code for provided URL and returns the short URL')
57
            )
58 2
            ->addArgument('longUrl', InputArgument::REQUIRED, $this->translator->translate('The long URL to parse'))
59 2
            ->addOption(
60 2
                'tags',
61 2
                't',
62 2
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
63 2
                $this->translator->translate('Tags to apply to the new short URL')
64
            )
65 2
            ->addOption('validSince', 's', InputOption::VALUE_REQUIRED, $this->translator->translate(
66
                'The date from which this short URL will be valid. '
67 2
                . 'If someone tries to access it before this date, it will not be found.'
68
            ))
69 2
            ->addOption('validUntil', 'u', InputOption::VALUE_REQUIRED, $this->translator->translate(
70
                'The date until which this short URL will be valid. '
71 2
                . 'If someone tries to access it after this date, it will not be found.'
72
            ))
73 2
            ->addOption('customSlug', 'c', InputOption::VALUE_REQUIRED, $this->translator->translate(
74 2
                'If provided, this slug will be used instead of generating a short code'
75
            ))
76 2
            ->addOption('maxVisits', 'm', InputOption::VALUE_REQUIRED, $this->translator->translate(
77 2
                'This will limit the number of visits for this short URL.'
78
            ));
79 2
    }
80
81 2
    protected function interact(InputInterface $input, OutputInterface $output): void
82
    {
83 2
        $io = new SymfonyStyle($input, $output);
84 2
        $longUrl = $input->getArgument('longUrl');
85 2
        if (! empty($longUrl)) {
86 2
            return;
87
        }
88
89
        $longUrl = $io->ask(
90
            $this->translator->translate('A long URL was not provided. Which URL do you want to be shortened?')
91
        );
92
        if (! empty($longUrl)) {
93
            $input->setArgument('longUrl', $longUrl);
94
        }
95
    }
96
97 2
    protected function execute(InputInterface $input, OutputInterface $output): void
98
    {
99 2
        $io = new SymfonyStyle($input, $output);
100 2
        $longUrl = $input->getArgument('longUrl');
101 2
        if (empty($longUrl)) {
102
            $io->error($this->translator->translate('A URL was not provided!'));
103
            return;
104
        }
105
106 2
        $tags = $input->getOption('tags');
107 2
        $processedTags = [];
108 2
        foreach ($tags as $key => $tag) {
109
            $explodedTags = \explode(',', $tag);
110
            $processedTags = \array_merge($processedTags, $explodedTags);
111
        }
112 2
        $tags = $processedTags;
113 2
        $customSlug = $input->getOption('customSlug');
114 2
        $maxVisits = $input->getOption('maxVisits');
115
116
        try {
117 2
            $shortCode = $this->urlShortener->urlToShortCode(
118 2
                new Uri($longUrl),
119 2
                $tags,
120 2
                $this->getOptionalDate($input, 'validSince'),
121 2
                $this->getOptionalDate($input, 'validUntil'),
122 2
                $customSlug,
123 2
                $maxVisits !== null ? (int) $maxVisits : null
124 1
            )->getShortCode();
125 1
            $shortUrl = $this->buildShortUrl($this->domainConfig, $shortCode);
126
127 1
            $io->writeln([
128 1
                \sprintf('%s <info>%s</info>', $this->translator->translate('Processed long URL:'), $longUrl),
129 1
                \sprintf('%s <info>%s</info>', $this->translator->translate('Generated short URL:'), $shortUrl),
130
            ]);
131 1
        } catch (InvalidUrlException $e) {
132 1
            $io->error(\sprintf(
133 1
                $this->translator->translate('Provided URL "%s" is invalid. Try with a different one.'),
134 1
                $longUrl
135
            ));
136
        } catch (NonUniqueSlugException $e) {
137
            $io->error(\sprintf(
138
                $this->translator->translate(
139
                    'Provided slug "%s" is already in use by another URL. Try with a different one.'
140
                ),
141
                $customSlug
142
            ));
143
        }
144 2
    }
145
146 2
    private function getOptionalDate(InputInterface $input, string $fieldName): ?\DateTime
147
    {
148 2
        $since = $input->getOption($fieldName);
149 2
        return $since !== null ? new \DateTime($since) : null;
150
    }
151
}
152