Completed
Push — master ( aca90e...8ef0e7 )
by Alejandro
10s
created

ListShortcodesCommand::execute()   C

Complexity

Conditions 8
Paths 24

Size

Total Lines 51
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 8.1039

Importance

Changes 0
Metric Value
cc 8
eloc 37
nc 24
nop 2
dl 0
loc 51
rs 6.5978
c 0
b 0
f 0
ccs 30
cts 34
cp 0.8824
crap 8.1039

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\CLI\Command\Shortcode;
5
6
use Shlinkio\Shlink\Common\Paginator\Adapter\PaginableRepositoryAdapter;
7
use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait;
8
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Console\Style\SymfonyStyle;
14
use Zend\I18n\Translator\TranslatorInterface;
15
16
class ListShortcodesCommand extends Command
17
{
18
    use PaginatorUtilsTrait;
19
20
    const NAME = 'shortcode:list';
21
22
    /**
23
     * @var ShortUrlServiceInterface
24
     */
25
    private $shortUrlService;
26
    /**
27
     * @var TranslatorInterface
28
     */
29
    private $translator;
30
31 5
    public function __construct(ShortUrlServiceInterface $shortUrlService, TranslatorInterface $translator)
32
    {
33 5
        $this->shortUrlService = $shortUrlService;
34 5
        $this->translator = $translator;
35 5
        parent::__construct();
36 5
    }
37
38 5
    public function configure()
39
    {
40 5
        $this->setName(self::NAME)
41 5
             ->setDescription($this->translator->translate('List all short URLs'))
42 5
             ->addOption(
43 5
                 'page',
44 5
                 'p',
45 5
                 InputOption::VALUE_OPTIONAL,
46 5
                 sprintf(
47 5
                     $this->translator->translate('The first page to list (%s items per page)'),
48 5
                     PaginableRepositoryAdapter::ITEMS_PER_PAGE
49
                 ),
50 5
                 1
51
             )
52 5
             ->addOption(
53 5
                 'searchTerm',
54 5
                 's',
55 5
                 InputOption::VALUE_OPTIONAL,
56 5
                 $this->translator->translate(
57 5
                     'A query used to filter results by searching for it on the longUrl and shortCode fields'
58
                 )
59
             )
60 5
             ->addOption(
61 5
                 'tags',
62 5
                 't',
63 5
                 InputOption::VALUE_OPTIONAL,
64 5
                 $this->translator->translate('A comma-separated list of tags to filter results')
65
             )
66 5
             ->addOption(
67 5
                 'orderBy',
68 5
                 'o',
69 5
                 InputOption::VALUE_OPTIONAL,
70 5
                 $this->translator->translate(
71 5
                     'The field from which we want to order by. Pass ASC or DESC separated by a comma'
72
                 )
73
             )
74 5
             ->addOption(
75 5
                 'showTags',
76 5
                 null,
77 5
                 InputOption::VALUE_NONE,
78 5
                 $this->translator->translate('Whether to display the tags or not')
79
             );
80 5
    }
81
82 5
    public function execute(InputInterface $input, OutputInterface $output)
83
    {
84 5
        $io = new SymfonyStyle($input, $output);
85 5
        $page = (int) $input->getOption('page');
86 5
        $searchTerm = $input->getOption('searchTerm');
87 5
        $tags = $input->getOption('tags');
88 5
        $tags = ! empty($tags) ? \explode(',', $tags) : [];
89 5
        $showTags = $input->getOption('showTags');
90
91
        do {
92 5
            $result = $this->shortUrlService->listShortUrls($page, $searchTerm, $tags, $this->processOrderBy($input));
93 5
            $page++;
94
95
            $headers = [
96 5
                $this->translator->translate('Short code'),
97 5
                $this->translator->translate('Original URL'),
98 5
                $this->translator->translate('Date created'),
99 5
                $this->translator->translate('Visits count'),
100
            ];
101 5
            if ($showTags) {
102 1
                $headers[] = $this->translator->translate('Tags');
103
            }
104
105 5
            $rows = [];
106 5
            foreach ($result as $row) {
107 2
                $shortUrl = $row->jsonSerialize();
108 2
                if ($showTags) {
109
                    $shortUrl['tags'] = [];
110
                    foreach ($row->getTags() as $tag) {
111
                        $shortUrl['tags'][] = $tag->getName();
112
                    }
113
                    $shortUrl['tags'] = implode(', ', $shortUrl['tags']);
114
                } else {
115 2
                    unset($shortUrl['tags']);
116
                }
117
118 2
                $rows[] = \array_values($shortUrl);
119
            }
120 5
            $io->table($headers, $rows);
121
122 5
            if ($this->isLastPage($result)) {
0 ignored issues
show
Bug introduced by
It seems like $result defined by $this->shortUrlService->...processOrderBy($input)) on line 92 can also be of type array<integer,object<Shl...\Core\Entity\ShortUrl>>; however, Shlinkio\Shlink\Common\P...tilsTrait::isLastPage() does only seem to accept object<Zend\Paginator\Paginator>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
123 3
                $continue = false;
124 3
                $io->success($this->translator->translate('Short codes properly listed'));
125
            } else {
126 2
                $continue = $io->confirm(
127 2
                    \sprintf($this->translator->translate('Continue with page') . ' <options=bold>%s</>?', $page),
128 2
                    false
129
                );
130
            }
131 5
        } while ($continue);
0 ignored issues
show
Bug Best Practice introduced by
The expression $continue of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
132 5
    }
133
134 5
    private function processOrderBy(InputInterface $input)
135
    {
136 5
        $orderBy = $input->getOption('orderBy');
137 5
        if (empty($orderBy)) {
138 5
            return null;
139
        }
140
141
        $orderBy = explode(',', $orderBy);
142
        return count($orderBy) === 1 ? $orderBy[0] : [$orderBy[0] => $orderBy[1]];
143
    }
144
}
145