Passed
Pull Request — master (#357)
by Alejandro
05:24
created

ListShortUrlsCommand::processOrderBy()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.3332

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
ccs 4
cts 6
cp 0.6667
crap 3.3332
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
5
6
use Shlinkio\Shlink\CLI\Util\ExitCodes;
7
use Shlinkio\Shlink\Common\Console\ShlinkTable;
8
use Shlinkio\Shlink\Common\Paginator\Adapter\PaginableRepositoryAdapter;
9
use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait;
10
use Shlinkio\Shlink\Common\Rest\DataTransformerInterface;
11
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
12
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
13
use Symfony\Component\Console\Command\Command;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Console\Style\SymfonyStyle;
18
use Zend\Paginator\Paginator;
19
use function array_values;
20
use function count;
21
use function explode;
22
use function implode;
23
use function sprintf;
24
25
class ListShortUrlsCommand extends Command
26
{
27
    use PaginatorUtilsTrait;
28
29
    public const NAME = 'short-url:list';
30
    private const ALIASES = ['shortcode:list', 'short-code:list'];
31
32
    /** @var ShortUrlServiceInterface */
33
    private $shortUrlService;
34
    /** @var array */
35
    private $domainConfig;
36
37 5
    public function __construct(ShortUrlServiceInterface $shortUrlService, array $domainConfig)
38
    {
39 5
        parent::__construct();
40 5
        $this->shortUrlService = $shortUrlService;
41 5
        $this->domainConfig = $domainConfig;
42
    }
43
44 5
    protected function configure(): void
45
    {
46
        $this
47 5
            ->setName(self::NAME)
48 5
            ->setAliases(self::ALIASES)
49 5
            ->setDescription('List all short URLs')
50 5
            ->addOption(
51 5
                'page',
52 5
                'p',
53 5
                InputOption::VALUE_OPTIONAL,
54 5
                sprintf('The first page to list (%s items per page)', PaginableRepositoryAdapter::ITEMS_PER_PAGE),
55 5
                '1'
56
            )
57 5
            ->addOption(
58 5
                'searchTerm',
59 5
                's',
60 5
                InputOption::VALUE_OPTIONAL,
61 5
                'A query used to filter results by searching for it on the longUrl and shortCode fields'
62
            )
63 5
            ->addOption(
64 5
                'tags',
65 5
                't',
66 5
                InputOption::VALUE_OPTIONAL,
67 5
                'A comma-separated list of tags to filter results'
68
            )
69 5
            ->addOption(
70 5
                'orderBy',
71 5
                'o',
72 5
                InputOption::VALUE_OPTIONAL,
73 5
                'The field from which we want to order by. Pass ASC or DESC separated by a comma'
74
            )
75 5
            ->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not');
76
    }
77
78 5
    protected function execute(InputInterface $input, OutputInterface $output): ?int
79
    {
80 5
        $io = new SymfonyStyle($input, $output);
81 5
        $page = (int) $input->getOption('page');
82 5
        $searchTerm = $input->getOption('searchTerm');
83 5
        $tags = $input->getOption('tags');
84 5
        $tags = ! empty($tags) ? explode(',', $tags) : [];
0 ignored issues
show
Bug introduced by
It seems like $tags can also be of type string[]; however, parameter $string of explode() 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

84
        $tags = ! empty($tags) ? explode(',', /** @scrutinizer ignore-type */ $tags) : [];
Loading history...
85 5
        $showTags = (bool) $input->getOption('showTags');
86 5
        $transformer = new ShortUrlDataTransformer($this->domainConfig);
87
88
        do {
89 5
            $result = $this->renderPage($input, $output, $page, $searchTerm, $tags, $showTags, $transformer);
90 5
            $page++;
91
92 5
            $continue = $this->isLastPage($result)
93 3
                ? false
94 5
                : $io->confirm(sprintf('Continue with page <options=bold>%s</>?', $page), false);
95 5
        } while ($continue);
96
97 5
        $io->newLine();
98 5
        $io->success('Short URLs properly listed');
99 5
        return ExitCodes::EXIT_SUCCESS;
100
    }
101
102 5
    private function renderPage(
103
        InputInterface $input,
104
        OutputInterface $output,
105
        int $page,
106
        ?string $searchTerm,
107
        array $tags,
108
        bool $showTags,
109
        DataTransformerInterface $transformer
110
    ): Paginator {
111 5
        $result = $this->shortUrlService->listShortUrls($page, $searchTerm, $tags, $this->processOrderBy($input));
112
113 5
        $headers = ['Short code', 'Short URL', 'Long URL', 'Date created', 'Visits count'];
114 5
        if ($showTags) {
115 1
            $headers[] = 'Tags';
116
        }
117
118 5
        $rows = [];
119 5
        foreach ($result as $row) {
120 2
            $shortUrl = $transformer->transform($row);
121 2
            if ($showTags) {
122
                $shortUrl['tags'] = implode(', ', $shortUrl['tags']);
123
            } else {
124 2
                unset($shortUrl['tags']);
125
            }
126
127 2
            unset($shortUrl['originalUrl']);
128 2
            $rows[] = array_values($shortUrl);
129
        }
130
131 5
        ShlinkTable::fromOutput($output)->render($headers, $rows, $this->formatCurrentPageMessage(
132 5
            $result,
133 5
            'Page %s of %s'
134
        ));
135 5
        return $result;
136
    }
137
138 5
    private function processOrderBy(InputInterface $input)
139
    {
140 5
        $orderBy = $input->getOption('orderBy');
141 5
        if (empty($orderBy)) {
142 5
            return null;
143
        }
144
145
        $orderBy = explode(',', $orderBy);
0 ignored issues
show
Bug introduced by
It seems like $orderBy can also be of type string[]; however, parameter $string of explode() 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

145
        $orderBy = explode(',', /** @scrutinizer ignore-type */ $orderBy);
Loading history...
146
        return count($orderBy) === 1 ? $orderBy[0] : [$orderBy[0] => $orderBy[1]];
147
    }
148
}
149