Completed
Push — develop ( a74e1d...e4f01e )
by Alejandro
28s queued 14s
created

GenerateShortUrlCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
6
7
use Shlinkio\Shlink\CLI\Util\ExitCodes;
8
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
9
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
10
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
11
use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
12
use Shlinkio\Shlink\Core\Validation\ShortUrlMetaInputFilter;
13
use Symfony\Component\Console\Command\Command;
14
use Symfony\Component\Console\Input\InputArgument;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Input\InputOption;
17
use Symfony\Component\Console\Output\OutputInterface;
18
use Symfony\Component\Console\Style\SymfonyStyle;
19
20
use function array_map;
21
use function Functional\curry;
22
use function Functional\flatten;
23
use function Functional\unique;
24
use function sprintf;
25
26
class GenerateShortUrlCommand extends Command
27
{
28
    public const NAME = 'short-url:generate';
29
30
    private UrlShortenerInterface $urlShortener;
31
    private array $domainConfig;
32
    private int $defaultShortCodeLength;
33
34 4
    public function __construct(UrlShortenerInterface $urlShortener, array $domainConfig, int $defaultShortCodeLength)
35
    {
36 4
        parent::__construct();
37 4
        $this->urlShortener = $urlShortener;
38 4
        $this->domainConfig = $domainConfig;
39 4
        $this->defaultShortCodeLength = $defaultShortCodeLength;
40
    }
41
42 4
    protected function configure(): void
43
    {
44
        $this
45 4
            ->setName(self::NAME)
46 4
            ->setDescription('Generates a short URL for provided long URL and returns it')
47 4
            ->addArgument('longUrl', InputArgument::REQUIRED, 'The long URL to parse')
48 4
            ->addOption(
49 4
                'tags',
50 4
                't',
51 4
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
52 4
                'Tags to apply to the new short URL',
53
            )
54 4
            ->addOption(
55 4
                'validSince',
56 4
                's',
57 4
                InputOption::VALUE_REQUIRED,
58
                'The date from which this short URL will be valid. '
59 4
                . 'If someone tries to access it before this date, it will not be found.',
60
            )
61 4
            ->addOption(
62 4
                'validUntil',
63 4
                'u',
64 4
                InputOption::VALUE_REQUIRED,
65
                'The date until which this short URL will be valid. '
66 4
                . 'If someone tries to access it after this date, it will not be found.',
67
            )
68 4
            ->addOption(
69 4
                'customSlug',
70 4
                'c',
71 4
                InputOption::VALUE_REQUIRED,
72 4
                'If provided, this slug will be used instead of generating a short code',
73
            )
74 4
            ->addOption(
75 4
                'maxVisits',
76 4
                'm',
77 4
                InputOption::VALUE_REQUIRED,
78 4
                'This will limit the number of visits for this short URL.',
79
            )
80 4
            ->addOption(
81 4
                'findIfExists',
82 4
                'f',
83 4
                InputOption::VALUE_NONE,
84 4
                'This will force existing matching URL to be returned if found, instead of creating a new one.',
85
            )
86 4
            ->addOption(
87 4
                'domain',
88 4
                'd',
89 4
                InputOption::VALUE_REQUIRED,
90 4
                'The domain to which this short URL will be attached.',
91
            )
92 4
            ->addOption(
93 4
                'shortCodeLength',
94 4
                'l',
95 4
                InputOption::VALUE_REQUIRED,
96 4
                'The length for generated short code (it will be ignored if --customSlug was provided).',
97
            );
98
    }
99
100 4
    protected function interact(InputInterface $input, OutputInterface $output): void
101
    {
102 4
        $io = new SymfonyStyle($input, $output);
103 4
        $longUrl = $input->getArgument('longUrl');
104 4
        if (! empty($longUrl)) {
105 4
            return;
106
        }
107
108
        $longUrl = $io->ask('Which URL do you want to shorten?');
109
        if (! empty($longUrl)) {
110
            $input->setArgument('longUrl', $longUrl);
111
        }
112
    }
113
114 4
    protected function execute(InputInterface $input, OutputInterface $output): ?int
115
    {
116 4
        $io = new SymfonyStyle($input, $output);
117 4
        $longUrl = $input->getArgument('longUrl');
118 4
        if (empty($longUrl)) {
119
            $io->error('A URL was not provided!');
120
            return ExitCodes::EXIT_FAILURE;
121
        }
122
123 4
        $explodeWithComma = curry('explode')(',');
124 4
        $tags = unique(flatten(array_map($explodeWithComma, $input->getOption('tags'))));
0 ignored issues
show
Bug introduced by
It seems like $input->getOption('tags') can also be of type boolean and null and string; however, parameter $arr1 of array_map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
        $tags = unique(flatten(array_map($explodeWithComma, /** @scrutinizer ignore-type */ $input->getOption('tags'))));
Loading history...
125 4
        $customSlug = $input->getOption('customSlug');
126 4
        $maxVisits = $input->getOption('maxVisits');
127 4
        $shortCodeLength = $input->getOption('shortCodeLength') ?? $this->defaultShortCodeLength;
128
129
        try {
130 4
            $shortUrl = $this->urlShortener->urlToShortCode($longUrl, $tags, ShortUrlMeta::fromRawData([
0 ignored issues
show
Bug introduced by
It seems like $longUrl can also be of type string[]; however, parameter $url of Shlinkio\Shlink\Core\Ser...rface::urlToShortCode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
            $shortUrl = $this->urlShortener->urlToShortCode(/** @scrutinizer ignore-type */ $longUrl, $tags, ShortUrlMeta::fromRawData([
Loading history...
131 4
                ShortUrlMetaInputFilter::VALID_SINCE => $input->getOption('validSince'),
132 4
                ShortUrlMetaInputFilter::VALID_UNTIL => $input->getOption('validUntil'),
133 4
                ShortUrlMetaInputFilter::CUSTOM_SLUG => $customSlug,
134 1
                ShortUrlMetaInputFilter::MAX_VISITS => $maxVisits !== null ? (int) $maxVisits : null,
135 4
                ShortUrlMetaInputFilter::FIND_IF_EXISTS => $input->getOption('findIfExists'),
136 4
                ShortUrlMetaInputFilter::DOMAIN => $input->getOption('domain'),
137 4
                ShortUrlMetaInputFilter::SHORT_CODE_LENGTH => $shortCodeLength,
138
            ]));
139
140 2
            $io->writeln([
141 2
                sprintf('Processed long URL: <info>%s</info>', $longUrl),
0 ignored issues
show
Bug introduced by
It seems like $longUrl can also be of type string[]; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
                sprintf('Processed long URL: <info>%s</info>', /** @scrutinizer ignore-type */ $longUrl),
Loading history...
142 2
                sprintf('Generated short URL: <info>%s</info>', $shortUrl->toString($this->domainConfig)),
143
            ]);
144 2
            return ExitCodes::EXIT_SUCCESS;
145 2
        } catch (InvalidUrlException | NonUniqueSlugException $e) {
146 2
            $io->error($e->getMessage());
147 2
            return ExitCodes::EXIT_FAILURE;
148
        }
149
    }
150
}
151