Completed
Push — develop ( eeebfd...e7b4cf )
by Andrea Marco
06:26
created

Drawer::drawBordered()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Cerbero\Workflow\Console\Drawing;
4
5
use Cerbero\Workflow\Repositories\PipelineRepositoryInterface;
6
7
/**
8
 * Class to generate the drawing.
9
 *
10
 * @author	Andrea Marco Sartori
11
 */
12
class Drawer
13
{
14
    const BORDER_X = '║';
15
16
    const BORDER_Y = '═';
17
18
    const BORDER_NW = '╔';
19
20
    const BORDER_NE = '╗';
21
22
    const BORDER_SE = '╝';
23
24
    const BORDER_SW = '╚';
25
26
    const NOCK = '║';
27
28
    const PILE = '∇';
29
30
    const CROSSROADS = '╬';
31
32
    const CROSSROADS_UP = '╩';
33
34
    const CROSSROADS_DOWN = '╦';
35
36
    /**
37
     * @author	Andrea Marco Sartori
38
     *
39
     * @var Cerbero\Workflow\Repositories\PipelineRepositoryInterface $pipelines	Pipeline repository.
40
     */
41
    protected $pipelines;
42
43
    /**
44
     * @author	Andrea Marco Sartori
45
     *
46
     * @var Cerbero\Workflow\Console\Drawing\Geometry $geometry	The applied geometry.
47
     */
48
    protected $geometry;
49
50
    /**
51
     * @author	Andrea Marco Sartori
52
     *
53
     * @var array $pipes	List of pipes.
54
     */
55
    protected $pipes;
56
57
    /**
58
     * @author	Andrea Marco Sartori
59
     *
60
     * @var string $drawing	The resulting drawing.
61
     */
62
    protected $drawing = '';
63
64
    /**
65
     * Set the dependencies.
66
     *
67
     * @author	Andrea Marco Sartori
68
     *
69
     * @param Cerbero\Workflow\Repositories\PipelineRepositoryInterface $pipelines
70
     * @param Cerbero\Workflow\Console\Drawing\Geometry                 $geometry
71
     *
72
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
73
     */
74 15
    public function __construct(PipelineRepositoryInterface $pipelines, Geometry $geometry)
75
    {
76 15
        $this->pipelines = $pipelines;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pipelines of type object<Cerbero\Workflow\...ineRepositoryInterface> is incompatible with the declared type object<Cerbero\Workflow\...ineRepositoryInterface> of property $pipelines.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
77
78 15
        $this->geometry = $geometry;
0 ignored issues
show
Documentation Bug introduced by
It seems like $geometry of type object<Cerbero\Workflow\Console\Drawing\Geometry> is incompatible with the declared type object<Cerbero\Workflow\...nsole\Drawing\Geometry> of property $geometry.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
79 15
    }
80
81
    /**
82
     * Draw the given workflow.
83
     *
84
     * @author	Andrea Marco Sartori
85
     *
86
     * @param string $workflow
87
     *
88
     * @return string
89
     */
90 12
    public function draw($workflow)
91
    {
92 12
        $this->geometry->setCore($workflow);
93
94 12
        $this->setPipesOfWorkflow($workflow);
95
96 12
        $this->drawCenteredChar(static::NOCK);
97
98 12
        $this->drawPipesBeginning();
99
100 12
        $this->drawCore();
101
102 12
        $this->drawPipesEnd();
103
104 12
        $this->drawCenteredChar(static::PILE);
105
106 12
        return $this->drawing;
107
    }
108
109
    /**
110
     * Set the pipes of the given workflow.
111
     *
112
     * @author	Andrea Marco Sartori
113
     *
114
     * @param string $workflow
115
     *
116
     * @return void
117
     */
118 12
    protected function setPipesOfWorkflow($workflow)
119
    {
120 12
        $pipes = $this->pipelines->getPipesByPipeline($workflow);
121
122 12
        $this->pipes = array_map(function ($pipe) {
123 9
            $chunks = explode('\\', $pipe);
124
125 9
            return end($chunks);
126
127 12
        }, $pipes);
128
129 12
        $this->geometry->setPipes($this->pipes);
130 12
    }
131
132
    /**
133
     * Draw a character in the middle of the drawing.
134
     *
135
     * @author	Andrea Marco Sartori
136
     *
137
     * @param string $character
138
     *
139
     * @return void
140
     */
141 12
    protected function drawCenteredChar($character)
142
    {
143 12
        $spaces = str_repeat(' ', $this->geometry->getHalfWidth());
144
145 12
        $this->drawRow($spaces.$character);
146 12
    }
147
148
    /**
149
     * Draw a row of the drawing.
150
     *
151
     * @author	Andrea Marco Sartori
152
     *
153
     * @param string $row
154
     *
155
     * @return void
156
     */
157 12
    protected function drawRow($row)
158
    {
159 12
        $this->drawing .= $row.PHP_EOL;
160 12
    }
161
162
    /**
163
     * Draw the beginning of all pipes.
164
     *
165
     * @author	Andrea Marco Sartori
166
     *
167
     * @return void
168
     */
169 12
    protected function drawPipesBeginning()
170
    {
171 12
        foreach ($this->pipes as $pipe) {
172 9
            $this->drawBorderTop();
173
174 9
            $this->drawBordered(
175 9
                $this->geometry->getSpacedPipe($pipe, static::NOCK, 'before()')
176 9
            );
177 12
        }
178 12
    }
179
180
    /**
181
     * Draw content wrapped by borders.
182
     *
183
     * @author	Andrea Marco Sartori
184
     *
185
     * @param string $content
186
     *
187
     * @return void
188
     */
189 12
    protected function drawBordered($content)
190
    {
191 12
        $left = $this->geometry->getLeftBordersWith(static::BORDER_X);
192
193 12
        $right = $this->geometry->getRightBordersWith(static::BORDER_X);
194
195 12
        $this->drawRow($left.$content.$right);
196 12
    }
197
198
    /**
199
     * Draw the top border.
200
     *
201
     * @author	Andrea Marco Sartori
202
     *
203
     * @param bool $isCore
204
     *
205
     * @return void
206
     */
207 12
    protected function drawBorderTop($isCore = false)
208
    {
209 12
        $crossroads = $isCore ? static::CROSSROADS_UP : static::CROSSROADS;
210
211 12
        $this->drawBorder(static::BORDER_NW, $crossroads, static::BORDER_NE);
212
213 12
        $this->geometry->increaseNesting();
214 12
    }
215
216
    /**
217
     * Draw a border with the given bendings.
218
     *
219
     * @author	Andrea Marco Sartori
220
     *
221
     * @param string $left
222
     * @param string $middle
223
     * @param string $right
224
     *
225
     * @return void
226
     */
227 12
    protected function drawBorder($left, $middle, $right)
228
    {
229 12
        $width = $this->geometry->getWidthButBorders();
230
231 12
        $border = str_repeat(static::BORDER_Y, $width);
232
233 12
        $this->replaceUtf8($border, $left, 0);
234 12
        $this->replaceUtf8($border, $middle, floor($width / 2));
235 12
        $this->replaceUtf8($border, $right, $width - 1);
236
237 12
        $this->drawBordered($border);
238 12
    }
239
240
    /**
241
     * Replace a character in a given position of a string.
242
     *
243
     * @author	Andrea Marco Sartori
244
     *
245
     * @param string $original
246
     * @param string $replacement
247
     * @param int    $position
248
     *
249
     * @return void
250
     */
251 12
    private function replaceUtf8(&$original, $replacement, $position)
252
    {
253 12
        $start = mb_substr($original, 0, $position, 'UTF-8');
254
255 12
        $end = mb_substr($original, $position + 1, mb_strlen($original, 'UTF-8'), 'UTF-8');
256
257 12
        $original = $start.$replacement.$end;
258 12
    }
259
260
    /**
261
     * Draw the core of the workflow.
262
     *
263
     * @author	Andrea Marco Sartori
264
     *
265
     * @return void
266
     */
267 12
    protected function drawCore()
268
    {
269 12
        $this->drawBorderTop(true);
270
271 12
        $this->drawBordered($this->geometry->getSpacedCore());
272
273 12
        $this->drawBorderBottom(true);
274 12
    }
275
276
    /**
277
     * Draw the bottom border.
278
     *
279
     * @author	Andrea Marco Sartori
280
     *
281
     * @param bool $isCore
282
     *
283
     * @return void
284
     */
285 12
    protected function drawBorderBottom($isCore = false)
286
    {
287 12
        $this->geometry->decreaseNesting();
288
289 12
        $crossroads = $isCore ? static::CROSSROADS_DOWN : static::CROSSROADS;
290
291 12
        $this->drawBorder(static::BORDER_SW, $crossroads, static::BORDER_SE);
292 12
    }
293
294
    /**
295
     * Draw the end of all pipes.
296
     *
297
     * @author	Andrea Marco Sartori
298
     *
299
     * @return void
300
     */
301 12
    protected function drawPipesEnd()
302
    {
303 12
        $pipes = array_reverse($this->pipes);
304
305 12
        foreach ($pipes as $pipe) {
306 9
            $this->drawBordered(
307 9
                $this->geometry->getSpacedPipe($pipe, static::NOCK, 'after()')
308 9
            );
309
310 9
            $this->drawBorderBottom();
311 12
        }
312 12
    }
313
}
314