Completed
Push — develop ( 9d3653...f17214 )
by Alejandro
16s queued 13s
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 Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand;
9
use Shlinkio\Shlink\CLI\Util\ExitCodes;
10
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
11
use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait;
12
use Shlinkio\Shlink\Common\Util\DateRange;
13
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
14
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
15
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Style\SymfonyStyle;
20
use Zend\Paginator\Paginator;
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 15
    private function renderPage(
126
        OutputInterface $output,
127
        int $page,
128
        ?string $searchTerm,
129
        array $tags,
130
        bool $showTags,
131
        ?Chronos $startDate,
132
        ?Chronos $endDate,
133
        $orderBy
134
    ): Paginator {
135 15
        $result = $this->shortUrlService->listShortUrls(
136 15
            $page,
137
            $searchTerm,
138
            $tags,
139
            $orderBy,
140 15
            new DateRange($startDate, $endDate)
141
        );
142
143 15
        $headers = ['Short code', 'Short URL', 'Long URL', 'Date created', 'Visits count'];
144 15
        if ($showTags) {
145 1
            $headers[] = 'Tags';
146
        }
147
148 15
        $rows = [];
149 15
        foreach ($result as $row) {
150 2
            $shortUrl = $this->transformer->transform($row);
151 2
            if ($showTags) {
152
                $shortUrl['tags'] = implode(', ', $shortUrl['tags']);
153
            } else {
154 2
                unset($shortUrl['tags']);
155
            }
156
157 2
            $rows[] = array_values(array_intersect_key($shortUrl, array_flip(self::COLUMNS_WHITELIST)));
158
        }
159
160 15
        ShlinkTable::fromOutput($output)->render($headers, $rows, $this->formatCurrentPageMessage(
161 15
            $result,
162 15
            'Page %s of %s'
163
        ));
164
165 15
        return $result;
166
    }
167
168
    /**
169
     * @return array|string|null
170
     */
171 15
    private function processOrderBy(InputInterface $input)
172
    {
173 15
        $orderBy = $input->getOption('orderBy');
174 15
        if (empty($orderBy)) {
175 12
            return null;
176
        }
177
178 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

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