Completed
Pull Request — master (#12)
by Harry
11:21
created

Table   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 230
Duplicated Lines 11.3 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 89.47%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 5
dl 26
loc 230
ccs 34
cts 38
cp 0.8947
rs 9.3999
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 12 12 3
B updateRowKeyLengths() 14 14 5
B formatRow() 0 14 5
B add() 0 41 4
A getSummary() 0 17 3
A render() 0 9 3
B run() 0 20 6
A isShowOutput() 0 4 1
A setShowOutput() 0 5 1
A isShowSummary() 0 4 1
A setShowSummary() 0 5 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * This file is part of graze/parallel-process.
4
 *
5
 * Copyright (c) 2017 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/parallel-process/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/parallel-process
12
 */
13
14
namespace Graze\ParallelProcess;
15
16
use Exception;
17
use Graze\DiffRenderer\DiffConsoleOutput;
18
use Graze\DiffRenderer\Terminal\TerminalInterface;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Process\Exception\ProcessFailedException;
21
use Symfony\Component\Process\Process;
22
23
class Table
24
{
25
    const SPINNER = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
26
27
    /** @var Pool */
28
    private $processPool;
29
    /** @var string[] */
30
    private $rows = [];
31
    /** @var Exception[] */
32
    private $exceptions;
33
    /** @var int[] */
34
    private $maxLengths = [];
35
    /** @var DiffConsoleOutput */
36
    private $output;
37
    /** @var TerminalInterface */
38
    private $terminal;
39
    /** @var bool */
40
    private $showOutput = true;
41
    /** @var bool */
42
    private $showSummary = true;
43
44
    /**
45
     * Table constructor.
46
     *
47
     * @param OutputInterface $output
48
     * @param Pool|null       $pool
49
     */
50 15 View Code Duplication
    public function __construct(OutputInterface $output, Pool $pool = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52 12
        $this->processPool = $pool ?: new Pool();
53 12
        if (!$output instanceof DiffConsoleOutput) {
54
            $this->output = new DiffConsoleOutput($output);
55
            $this->output->setTrim(true);
56
        } else {
57 15
            $this->output = $output;
58 3
        }
59
        $this->terminal = $this->output->getTerminal();
60 12
        $this->exceptions = [];
61
    }
62
63
    /**
64
     * Parses the rows to determine the key lengths to make a pretty table
65
     *
66
     * @param array $data
67
     */
68 2 View Code Duplication
    private function updateRowKeyLengths(array $data = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
    {
70
        $lengths = array_map('mb_strlen', $data);
71
72
        $keys = array_merge(array_keys($lengths), array_keys($this->maxLengths));
73
74
        foreach ($keys as $key) {
75 2
            if (!isset($this->maxLengths[$key])
76
                || (isset($lengths[$key]) && $lengths[$key] > $this->maxLengths[$key])
77
            ) {
78 2
                $this->maxLengths[$key] = $lengths[$key];
79
            }
80
        }
81
    }
82
83
    /**
84
     * @param array  $data
85
     * @param string $status
86
     * @param float  $duration
87
     * @param string $extra
88
     *
89
     * @return string
90
     */
91
    private function formatRow(array $data, $status, $duration, $extra = '')
92
    {
93
        $info = [];
94
        foreach ($data as $key => $value) {
95
            $length = isset($this->maxLengths[$key]) ? '-' . $this->maxLengths[$key] : '';
96
            if (is_int($key)) {
97
                $info[] = sprintf("%{$length}s", $value);
98
            } else {
99
                $info[] = sprintf("<info>%s</info>: %{$length}s", $key, $value);
100
            }
101
        }
102
        $extra = $extra ? '  ' . $this->terminal->filter($extra) : '';
103
        return sprintf("%s (<comment>%6.2fs</comment>) %s%s", implode(' ', $info), $duration, $status, $extra);
104
    }
105
106
    /**
107
     * @param Process $process
108
     * @param array   $data
109
     */
110 8
    public function add(Process $process, array $data = [])
111
    {
112
        $index = count($this->rows);
113
        $this->rows[$index] = $this->formatRow($data, '', 0);
114 8
        $spinner = 0;
115
116
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
117
            $onProgress = function ($process, $duration, $last) use ($index, $data, &$spinner) {
118 5
                $this->rows[$index] = $this->formatRow(
119
                    $data,
120 5
                    mb_substr(static::SPINNER, $spinner++, 1),
121
                    $duration,
122 5
                    ($this->showOutput ? $last : '')
123
                );
124
                if ($spinner > mb_strlen(static::SPINNER) - 1) {
125 1
                    $spinner = 0;
126
                }
127
                $this->render();
128
            };
129
        } else {
130 2
            $onProgress = null;
131 6
        }
132
133
        $run = new Run(
134
            $process,
135
            function ($process, $duration, $last) use ($index, $data) {
136
                $this->rows[$index] = $this->formatRow($data, "<info>✓</info>", $duration, $last);
137
                $this->render($index);
138 2
            },
139 6
            function ($process, $duration, $last) use ($index, $data) {
140
                $this->rows[$index] = $this->formatRow($data, "<error>x</error>", $duration, $last);
141
                $this->render($index);
142
                $this->exceptions[] = new ProcessFailedException($process);
143 6
            },
144
            $onProgress
145
        );
146
        $run->setUpdateOnProcessOutput(false);
147
        $this->processPool->add($run);
148
149
        $this->updateRowKeyLengths($data);
150
    }
151
152
    /**
153
     * @return string
154
     */
155 1
    private function getSummary()
156
    {
157
        if ($this->processPool->hasStarted()) {
158
            if ($this->processPool->isRunning()) {
159
                return sprintf(
160
                    '<comment>Total</comment>: %2d, <comment>Running</comment>: %2d, <comment>Waiting</comment>: %2d',
161
                    $this->processPool->count(),
162
                    count($this->processPool->getRunning()),
163
                    count($this->processPool->getWaiting())
164
                );
165
            } else {
166 1
                return '';
167
            }
168
        } else {
169 1
            return 'waiting...';
170
        }
171
    }
172
173
    /**
174
     * Render a specific row
175
     *
176
     * @param int $row
177
     */
178 2
    private function render($row = 0)
179
    {
180
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
181
            $rows = ($this->showSummary ? array_merge($this->rows, [$this->getSummary()]) : $this->rows);
182
            $this->output->reWrite($rows, !$this->showSummary);
183
        } else {
184
            $this->output->writeln($this->rows[$row]);
185
        }
186 2
    }
187
188
    /**
189
     * @param float $checkInterval
190
     *
191
     * @return bool true if all processes were successful
192
     * @throws Exception
193
     */
194 9
    public function run($checkInterval = Pool::CHECK_INTERVAL)
195
    {
196
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
197
            $this->render();
198
        }
199
        $output = $this->processPool->run($checkInterval);
200
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE && $this->showSummary) {
201
            $this->render();
202
        }
203
204
        if (count($this->exceptions) > 0) {
205 3
            foreach ($this->exceptions as $exception) {
206
                $this->output->writeln($exception->getMessage());
207
            }
208
209
            throw reset($this->exceptions);
210
        }
211
212 9
        return $output;
213
    }
214
215
    /**
216
     * @return bool
217
     */
218
    public function isShowOutput()
219
    {
220
        return $this->showOutput;
221
    }
222
223
    /**
224
     * @param bool $showOutput
225
     *
226
     * @return $this
227
     */
228 11
    public function setShowOutput($showOutput)
229
    {
230 11
        $this->showOutput = $showOutput;
231 11
        return $this;
232
    }
233
234
    /**
235
     * @return bool
236
     */
237
    public function isShowSummary()
238
    {
239
        return $this->showSummary;
240
    }
241
242
    /**
243
     * @param bool $showSummary
244
     *
245
     * @return $this
246
     */
247 13
    public function setShowSummary($showSummary)
248
    {
249 13
        $this->showSummary = $showSummary;
250 13
        return $this;
251
    }
252
}
253