Passed
Pull Request — develop (#579)
by Alejandro
05:16
created

ListShortUrlsCommand::renderPage()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 4.0016

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
ccs 20
cts 21
cp 0.9524
crap 4.0016
rs 9.584

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 ALIASES = ['shortcode:list', 'short-code:list'];
36
    private const COLUMNS_WHITELIST = [
37
        'shortCode',
38
        'shortUrl',
39
        'longUrl',
40
        'dateCreated',
41
        'visitsCount',
42
        'tags',
43
    ];
44
45
    /** @var ShortUrlServiceInterface */
46
    private $shortUrlService;
47
    /** @var ShortUrlDataTransformer */
48
    private $transformer;
49
50 15
    public function __construct(ShortUrlServiceInterface $shortUrlService, array $domainConfig)
51
    {
52 15
        parent::__construct();
53 15
        $this->shortUrlService = $shortUrlService;
54 15
        $this->transformer = new ShortUrlDataTransformer($domainConfig);
55
    }
56
57 15
    protected function doConfigure(): void
58
    {
59
        $this
60 15
            ->setName(self::NAME)
61 15
            ->setAliases(self::ALIASES)
62 15
            ->setDescription('List all short URLs')
63 15
            ->addOption(
64 15
                'page',
65 15
                'p',
66 15
                InputOption::VALUE_REQUIRED,
67 15
                sprintf('The first page to list (%s items per page)', ShortUrlRepositoryAdapter::ITEMS_PER_PAGE),
68 15
                '1'
69
            )
70 15
            ->addOption(
71 15
                'searchTerm',
72 15
                'st',
73 15
                InputOption::VALUE_REQUIRED,
74 15
                'A query used to filter results by searching for it on the longUrl and shortCode fields'
75
            )
76 15
            ->addOption(
77 15
                'tags',
78 15
                't',
79 15
                InputOption::VALUE_REQUIRED,
80 15
                'A comma-separated list of tags to filter results'
81
            )
82 15
            ->addOption(
83 15
                'orderBy',
84 15
                'o',
85 15
                InputOption::VALUE_REQUIRED,
86 15
                'The field from which we want to order by. Pass ASC or DESC separated by a comma'
87
            )
88 15
            ->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not');
89
    }
90
91 15
    protected function getStartDateDesc(): string
92
    {
93 15
        return 'Allows to filter short URLs, returning only those created after "startDate"';
94
    }
95
96 15
    protected function getEndDateDesc(): string
97
    {
98 15
        return 'Allows to filter short URLs, returning only those created before "endDate"';
99
    }
100
101 15
    protected function execute(InputInterface $input, OutputInterface $output): ?int
102
    {
103 15
        $io = new SymfonyStyle($input, $output);
104
105 15
        $page = (int) $input->getOption('page');
106 15
        $searchTerm = $input->getOption('searchTerm');
107 15
        $tags = $input->getOption('tags');
108 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

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

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