ListTasks::display()   C
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 39
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 8.8142

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 16
cts 24
cp 0.6667
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 24
nc 6
nop 3
crap 8.8142
1
<?php
2
3
namespace JobQueue\Application\Console;
4
5
use JobQueue\Application\Utils\CommandTrait;
6
use JobQueue\Domain\Task\Profile;
7
use JobQueue\Domain\Task\Status;
8
use Symfony\Component\Console\Helper\Table;
9
use Symfony\Component\Console\Helper\TableCell;
10
use Symfony\Component\Console\Helper\TableSeparator;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
15
final class ListTasks extends ManagerCommand
16
{
17
    use CommandTrait;
18
19
    /**
20
     *
21
     * @var Profile
22
     */
23
    private $profile;
24
25
    /**
26
     *
27
     * @var Status
28
     */
29
    private $status;
30
31
    /**
32
     *
33
     * @var array
34
     */
35
    private $tags = [];
36
37
    public function configure()
38
    {
39
        $this
40
            ->setName('list')
41
            ->setDescription('Lists tasks')
42
            ->addOption('profile', 'p', InputOption::VALUE_OPTIONAL, 'Limits the listing to a profile')
43
            ->addOption('status',  's', InputOption::VALUE_OPTIONAL, 'Limits the listing to a status')
44
            ->addOption('tags',    't', InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'Limits the listing to one or many (array) tags')
45
            ->addOption('order',   'o', InputOption::VALUE_REQUIRED, 'Orders tasks by "date", "profile" or "status"', 'status')
46
            ->addOption('follow',  'f', InputOption::VALUE_NONE, 'Enables to keep tasks evolution on the console')
47
            ->addOption('legend',  'l', InputOption::VALUE_NONE, 'Displays a legend for status labels at the list footer')
48
        ;
49
    }
50
51
    /**
52
     *
53
     * @param InputInterface $input
54
     * @param OutputInterface $output
55
     * @return int
56
     */
57 3
    protected function execute(InputInterface $input, OutputInterface $output): int
58
    {
59 3
        $this->setStyles($output);
60
61 3
        $this->profile = $input->getOption('profile')
62 1
            ? new Profile($input->getOption('profile'))
63 2
            : null;
64
65 3
        $this->status = $input->getOption('status')
66
            ? new Status($input->getOption('status'))
67 3
            : null;
68
69 3
        $this->tags = is_array($input->getOption('tags'))
70 3
            ? $input->getOption('tags')
71
            : [];
72
73
        // Clear screen for `follow` mode
74 3
        if ($follow = $input->getOption('follow')) {
75
            system('clear');
76
        }
77
78 3
        $this->display($follow, $input, $output);
79
80 3
        return 0;
81
    }
82
83
    /**
84
     *
85
     * @param bool            $follow
86
     * @param InputInterface  $input
87
     * @param OutputInterface $output
88
     */
89 3
    private function display(bool $follow, InputInterface $input, OutputInterface $output)
90
    {
91 3
        list($rows, $taskCount) = $this->getRows($input->getOption('order'), $output);
92
93 3
        if (empty($rows)) {
94
            $this->formatInfoBlock(
95
                sprintf('There is currently no task corresponding to %s profile and %s status in queue.',
96
                    $this->profile ?: 'any',
97
                    $this->status ?: 'any'),
98
                $output
99
            );
100
101
        } else {
102 3
            if ($input->getOption('legend')) {
103 2
                $rows = $this->addTableFooter($rows, $output);
104
            }
105
106 3
            $columns = ['Job', 'Profile', 'Date'];
107 3
            foreach ($this->tags as $key => $tag) {
108 1
                $columns[] = sprintf('T%d', $key + 1);
109
            }
110 3
            $columns[] = 'Identifier';
111
112 3
            (new Table($output))
113 3
                ->setHeaders($columns)
114 3
                ->setRows($rows)
115 3
                ->render()
116
            ;
117
118 3
            $output->writeln(sprintf('There is %d tasks in queue', $taskCount));
119 3
            $output->writeln('');
120
        }
121
122
        // follow mode
123 3
        if ($follow) {
124
            sleep(1);
125
            system('clear');
126
127
            $this->display($follow, $input, $output);
128
        }
129 3
    }
130
131
    /**
132
     *
133
     * @param string          $order
134
     * @param OutputInterface $output
135
     * @return array
136
     */
137 3
    public function getRows(string $order, OutputInterface $output): array
138
    {
139 3
        $taskCount = 0;
140 3
        $rows = [];
141 3
        $previousSeparator = null;
142
143 3
        foreach ($this->queue->search($this->profile, $this->status, $this->tags, $order) as $task) {
144 3
            $status = (string) $task->getStatus();
145
146
            // When no specific status is required in the command line,
147
            // then do not display `finished` tasks (this is arbitrary)
148 3
            if (is_null($this->status)) {
149 3
                if (Status::FINISHED === $status) continue;
150
            }
151
152 3
            $taskCount++;
153
154 3
            $profile = (string) $task->getProfile();
155
156
            switch ($order) {
157 3
                case 'date':
158
                    $separator = $task->getCreatedAt('Ymd');
159
                    break;
160
161 3
                case 'profile':
162
                    $separator = $profile;
163
                    break;
164
165 3
                case 'status':
166
                default:
167 3
                    $separator = $status;
168
            }
169
170 3
            if ($previousSeparator and $separator !== $previousSeparator) {
171
                $rows[] = new TableSeparator;
172
            }
173
174
            $taskData = [
175 3
                sprintf('%s %s', $this->formatContent('■', $status, $output), $task->getJobName(true)),
176 3
                $profile,
177 3
                $task->getCreatedAt('Y-m-d H:i:s'),
178
            ];
179
180
            // Add `tags` columns
181 3
            foreach ($this->tags as $tag) {
182 1
                $taskData[] = $task->hasTag($tag) ? ' ✔ ' : ' ✘ ';
183
            }
184
185 3
            $taskData[] = $task->getIdentifier();
186
187 3
            $rows[] = $taskData;
188
189 3
            $previousSeparator = $separator;
190
        }
191
192 3
        return [$rows, $taskCount];
193
    }
194
195
    /**
196
     *
197
     * @param array $rows
198
     * @param OutputInterface $output
199
     * @return array
200
     */
201 2
    private function addTableFooter(array $rows, OutputInterface $output): array
202
    {
203 2
        $legend = [];
204 2
        foreach (Status::listStatus() as $status) {
205 2
            $legend[] = sprintf('%s %s', $this->formatContent('■', $status, $output), $status);
206
        }
207
208 2
        $colspan = count(Status::listStatus()) + count($this->tags);
209
210 2
        $rows[] = new TableSeparator;
211 2
        $rows[] = [new TableCell(
212 2
            sprintf('Legend:   %s', implode('   ', $legend)),
213 2
            ['colspan' => $colspan]
214
        )];
215
216 2
        if (!empty($this->tags)) {
217 1
            $tags = [];
218 1
            foreach ($this->tags as $key => $tag) {
219 1
                $tags[] = sprintf('- T%s: tag "%s"', $key + 1, $tag);
220
            }
221
222 1
            $rows[] = [new TableCell(
223 1
                sprintf("Tag(s): \n%s", implode("\n", $tags)),
224 1
                ['colspan' => $colspan]
225
            )];
226
        }
227
228 2
        return $rows;
229
    }
230
}
231