Passed
Branch master (aecce8)
by Brice
05:03
created

ListTasks::display()   C

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