Completed
Pull Request — master (#604)
by Alejandro
11:57 queued 08:51
created

ListShortUrlsCommand::renderPage()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4.0027

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 21
c 1
b 0
f 0
nc 6
nop 8
dl 0
loc 41
rs 9.584
ccs 17
cts 18
cp 0.9444
crap 4.0027

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
6
7
use Cake\Chronos\Chronos;
8
use Laminas\Paginator\Paginator;
9
use Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand;
10
use Shlinkio\Shlink\CLI\Util\ExitCodes;
11
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
12
use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait;
13
use Shlinkio\Shlink\Common\Util\DateRange;
14
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
15
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
16
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Console\Style\SymfonyStyle;
21
22
use function array_flip;
23
use function array_intersect_key;
24
use function array_values;
25
use function count;
26
use function explode;
27
use function implode;
28
use function sprintf;
29
30
class ListShortUrlsCommand extends AbstractWithDateRangeCommand
31
{
32
    use PaginatorUtilsTrait;
33
34
    public const NAME = 'short-url:list';
35
    private const COLUMNS_WHITELIST = [
36
        'shortCode',
37
        'shortUrl',
38
        'longUrl',
39
        'dateCreated',
40
        'visitsCount',
41
        'tags',
42
    ];
43
44
    private ShortUrlServiceInterface $shortUrlService;
45
    private ShortUrlDataTransformer $transformer;
46
47 15
    public function __construct(ShortUrlServiceInterface $shortUrlService, array $domainConfig)
48
    {
49 15
        parent::__construct();
50 15
        $this->shortUrlService = $shortUrlService;
51 15
        $this->transformer = new ShortUrlDataTransformer($domainConfig);
52
    }
53
54 15
    protected function doConfigure(): void
55
    {
56
        $this
57 15
            ->setName(self::NAME)
58 15
            ->setDescription('List all short URLs')
59 15
            ->addOption(
60 15
                'page',
61 15
                'p',
62 15
                InputOption::VALUE_REQUIRED,
63 15
                sprintf('The first page to list (%s items per page)', ShortUrlRepositoryAdapter::ITEMS_PER_PAGE),
64 15
                '1',
65
            )
66 15
            ->addOption(
67 15
                'searchTerm',
68 15
                'st',
69 15
                InputOption::VALUE_REQUIRED,
70 15
                'A query used to filter results by searching for it on the longUrl and shortCode fields',
71
            )
72 15
            ->addOption(
73 15
                'tags',
74 15
                't',
75 15
                InputOption::VALUE_REQUIRED,
76 15
                'A comma-separated list of tags to filter results',
77
            )
78 15
            ->addOption(
79 15
                'orderBy',
80 15
                'o',
81 15
                InputOption::VALUE_REQUIRED,
82 15
                'The field from which we want to order by. Pass ASC or DESC separated by a comma',
83
            )
84 15
            ->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not');
85
    }
86
87 15
    protected function getStartDateDesc(): string
88
    {
89 15
        return 'Allows to filter short URLs, returning only those created after "startDate"';
90
    }
91
92 15
    protected function getEndDateDesc(): string
93
    {
94 15
        return 'Allows to filter short URLs, returning only those created before "endDate"';
95
    }
96
97 15
    protected function execute(InputInterface $input, OutputInterface $output): ?int
98
    {
99 15
        $io = new SymfonyStyle($input, $output);
100
101 15
        $page = (int) $input->getOption('page');
102 15
        $searchTerm = $input->getOption('searchTerm');
103 15
        $tags = $input->getOption('tags');
104 15
        $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

104
        $tags = ! empty($tags) ? explode(',', /** @scrutinizer ignore-type */ $tags) : [];
Loading history...
105 15
        $showTags = (bool) $input->getOption('showTags');
106 15
        $startDate = $this->getDateOption($input, $output, 'startDate');
107 15
        $endDate = $this->getDateOption($input, $output, 'endDate');
108 15
        $orderBy = $this->processOrderBy($input);
109
110
        do {
111 15
            $result = $this->renderPage($output, $page, $searchTerm, $tags, $showTags, $startDate, $endDate, $orderBy);
112 15
            $page++;
113
114 15
            $continue = $this->isLastPage($result)
115 13
                ? false
116 15
                : $io->confirm(sprintf('Continue with page <options=bold>%s</>?', $page), false);
117 15
        } while ($continue);
118
119 15
        $io->newLine();
120 15
        $io->success('Short URLs properly listed');
121
122 15
        return ExitCodes::EXIT_SUCCESS;
123
    }
124
125
    /**
126
     * @param string|array|null $orderBy
127
     */
128 15
    private function renderPage(
129
        OutputInterface $output,
130
        int $page,
131
        ?string $searchTerm,
132
        array $tags,
133
        bool $showTags,
134
        ?Chronos $startDate,
135
        ?Chronos $endDate,
136
        $orderBy
137
    ): Paginator {
138 15
        $result = $this->shortUrlService->listShortUrls(
139 15
            $page,
140
            $searchTerm,
141
            $tags,
142
            $orderBy,
143 15
            new DateRange($startDate, $endDate),
144
        );
145
146 15
        $headers = ['Short code', 'Short URL', 'Long URL', 'Date created', 'Visits count'];
147 15
        if ($showTags) {
148 1
            $headers[] = 'Tags';
149
        }
150
151 15
        $rows = [];
152 15
        foreach ($result as $row) {
153 2
            $shortUrl = $this->transformer->transform($row);
154 2
            if ($showTags) {
155
                $shortUrl['tags'] = implode(', ', $shortUrl['tags']);
156
            } else {
157 2
                unset($shortUrl['tags']);
158
            }
159
160 2
            $rows[] = array_values(array_intersect_key($shortUrl, array_flip(self::COLUMNS_WHITELIST)));
161
        }
162
163 15
        ShlinkTable::fromOutput($output)->render($headers, $rows, $this->formatCurrentPageMessage(
164 15
            $result,
165 15
            'Page %s of %s',
166
        ));
167
168 15
        return $result;
169
    }
170
171
    /**
172
     * @return array|string|null
173
     */
174 15
    private function processOrderBy(InputInterface $input)
175
    {
176 15
        $orderBy = $input->getOption('orderBy');
177 15
        if (empty($orderBy)) {
178 12
            return null;
179
        }
180
181 3
        $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

181
        $orderBy = explode(',', /** @scrutinizer ignore-type */ $orderBy);
Loading history...
182 3
        return count($orderBy) === 1 ? $orderBy[0] : [$orderBy[0] => $orderBy[1]];
183
    }
184
}
185