Passed
Push — master ( 7dd436...9d828a )
by Roman
02:49
created

AbstractFormatter::addRows()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace ToolkitLab\ASCII;
4
5
use ToolkitLab\ASCII\Table;
6
7
abstract class AbstractFormatter implements FormatterInterface {
8
    
9
    const
10
        DEFAULT_MODE              = 0x00,
11
12
        HEADER_FIRST_ROW_MODE     = 0X01,
13
        HEADER_NUMERIC_MODE       = 0x02,
14
        HEADER_ABC_MODE           = 0X04,
15
            
16
        SIDEBAR_NUMERIC_MODE      = 0X10,
17
        SIDEBAR_ABC_MODE          = 0x20,
18
            
19
        SPREADSHEET_MODE          = 0X14;
20
21
    /**
22
     * @var Table
23
     */
24
    protected $table;
25
26
    /**
27
     * @var array
28
     */
29
    protected $metadata = [];
30
31
    /**
32
     * @var string
33
     */
34
    protected $output = '';
35
36
    /**
37
     * The data to be formatted
38
     * @var array
39
     */
40
    protected $data = [];
41
    
42
    /**
43
     * @var boolean
44
     */
45
    protected $useHeader = false;
46
    
47
    /**
48
     * @var boolean
49
     */
50
    protected $useSidebar = false;
51
52
    /**
53
     * Formatting parameters
54
     * @var array
55
     */
56
    protected $params = [
57
        'mode' => self::DEFAULT_MODE,
58
        'rotate' => false,
59
        'max_cell_length' => 100,
60
        'max_cell_ending' => '...',
61
    ];
62
63
    /**
64
     * Constructor
65
     * @param array $params
66
     */
67 40
    public function __construct($params = []) {
68 40
        $this->setParams($params);
69 38
    }
70
71
    /**
72
     * Converts an array into ASCII-formatted string (table)
73
     * @param mixed $data
74
     * @param array $params
75
     * @return string
76
     */
77 38
    public function format($data, $params = []) {
78 38
        $table = $data instanceof Table ? $data : new Table($data);
79 38
        $this->init($table, $params);
80 34
        $this->addTopBorder();
81 34
        $this->addHeader();
82 34
        $this->addRows();
83 34
        $this->addBottomBorder();
84 34
        return $this->output;
85
    }
86
87
    /**
88
     * Initializes the data/parameters before formatting
89
     * @param Table $table
90
     * @param array $params
91
     * @return void
92
     */
93 38
    protected function init(Table $table, $params = []) {
94 38
        $this->output = '';
95 38
        $this->setParams($params);
96 38
        $this->table = $table;
97 38
        if ($this->getParam('rotate') !== false) {
98 8
            $this->table->rotate($this->getParam('rotate'));
99 4
        }
100 38
        $this->initSidebar();
101 36
        $this->initHeader();
102 34
        $maxLength = $this->getParam('max_cell_length');
103 34
        $ending = $this->getParam('max_cell_ending');
104 34
        $this->table->truncate($maxLength, $ending);
105 34
    }
106
    
107
    /**
108
     * Initializes the header
109
     * @throws \LogicException
110
     */
111 36
    protected function initHeader() {
112 36
        $count = 0;
113 36
        $mode = $this->getParam('mode');
114 36
        $data = $this->table->getData();
115 36
        $x = $this->table->getDimensionX();
116
        
117 36
        if (($mode & self::HEADER_FIRST_ROW_MODE) === self::HEADER_FIRST_ROW_MODE) {
118 10
            $count++;
119 5
        }
120
        
121 36
        if (($mode & self::HEADER_ABC_MODE) === self::HEADER_ABC_MODE) {
122 6
            $data = array_merge([$this->getAbcRange($x, $this->useSidebar)], $data);
123 6
            $count++;
124 3
        }
125
        
126 36
        if (($mode & self::HEADER_NUMERIC_MODE) === self::HEADER_NUMERIC_MODE) {
127 4
            $data = array_merge([$this->getNumRange($x, $this->useSidebar)], $data);
128 4
            $count++;
129 2
        }
130
        
131 36
        if ($count > 1) {
132 2
            throw new \LogicException('There should be only one header.');
133
        }
134
        
135 34
        if ($count) {
136 16
            $this->useHeader = true;
137 16
            $this->table->setData($data);
138 8
        }
139 34
    }
140
    
141
    /**
142
     * Initializes the sidebar
143
     * @throws \LogicException
144
     */
145 38
    protected function initSidebar() {
146 38
        $count = 0;
147 38
        $mode = $this->getParam('mode');
148 38
        $data = $this->table->getData();
149 38
        $headerMode = ($mode & self::HEADER_FIRST_ROW_MODE) === self::HEADER_FIRST_ROW_MODE;
150 38
        $y = $this->table->getDimensionY();
151
        
152 38
        if (($mode & self::SIDEBAR_ABC_MODE) === self::SIDEBAR_ABC_MODE) {
153 4
            $abc = $this->getAbcRange($y, $headerMode);
154 4
            foreach ($data as $key => $val) {
155 4
                $data[$key] = array_merge([array_shift($abc)], $val);
156 2
            }
157 4
            $count++;
158 2
        }
159
        
160 38
        if (($mode & self::SIDEBAR_NUMERIC_MODE) === self::SIDEBAR_NUMERIC_MODE) {
161 4
            $num = $this->getNumRange($y, $headerMode);
162 4
            foreach ($data as $key => $val) {
163 4
                $data[$key] = array_merge([array_shift($num)], $val);
164 2
            }
165 4
            $count++;
166 2
        }
167
        
168 38
        if ($count > 1) {
169 2
            throw new \LogicException('There should be only one sidebar.');
170
        }
171
        
172 36
        if ($count) {
173 4
            $this->useSidebar = true;
174 4
            $this->table->setData($data);
175 2
        }
176 36
    }
177
    
178
    /**
179
     * Updates the parameters with new values
180
     * @param array $params
181
     * @throws \InvalidArgumentException
182
     */
183 40
    protected function setParams($params) {
184 40
        $unknownParams = array_diff(array_keys($params), array_keys($this->params));
185 40
        if (count($unknownParams)) {
186 2
            throw new \InvalidArgumentException('Unknown parameter(-s): ' . implode(', ', $unknownParams));
187
        }
188 38
        $this->params = array_merge($this->params, $params);
189 38
    }
190
191
    /**
192
     * Get the specified parameter
193
     * @param string $key
194
     * @return mixed
195
     */
196 38
    protected function getParam($key) {
197 38
        return $this->params[$key];
198
    }
199
    
200
    /**
201
     * Returns an array of letters for a spreadsheet header
202
     * @param int $length
203
     * @return array
204
     */
205 10
    final protected function getAbcRange($length, $firstEmpty = false) {
206 10
        $length = $firstEmpty ? $length - 1 : $length;
207 10
        $baseRange = range('A', 'Z');
208 10
        $range = range('A', 'Z');
209 10
        while (count($range) < $length && count($baseRange) > 1) {
210 2
            $letter = array_shift($baseRange);
211 2
            $tmpRange = range('A', 'Z');
212
            array_walk($tmpRange, function(&$e) use ($letter) { $e = $letter . $e; });
213 2
            $range = array_merge($range, $tmpRange);
214 1
        }
215 10
        $range = array_slice($range, 0, $length);
216 10
        if ($firstEmpty) {
217 2
            $range = array_merge([''], $range);
218 1
        }
219 10
        return $range;
220
    }
221
    
222
    /**
223
     * Returns an array of digits for a spreadsheet header
224
     * @param int $length
225
     * @return array
226
     */
227 8
    final protected function getNumRange($length, $firstEmpty = false) {
228 8
        $length = $firstEmpty ? $length - 1 : $length;
229 8
        $range = range(1, $length);
230 8
        if ($firstEmpty) {
231
            $range = array_merge([''], $range);
232
        }
233 8
        return $range;
234
    }
235
236
    /**
237
     * Adds the top border to the output
238
     * @return void
239
     */
240 34
    protected function addTopBorder() {
241 34
        if ($this->metadata['top_border']) {
242 30
            $this->addRow(
243 30
                $this->metadata['top_border']['left'],
244 30
                $this->metadata['top_border']['middle'],
245 30
                $this->metadata['top_border']['right'],
246 30
                $this->metadata['top_border']['pad']
247 15
            );
248 15
        }
249 34
    }
250
251
    /**
252
     * Adds the header row to the output
253
     * @return void
254
     */
255 34
    protected function addHeader() {
256 34
        if ($this->useHeader) {
257 16
            $data = $this->table->getData();
258 16
            $x = $this->table->getDimensionX();
259 16
            $y = $this->table->getDimensionY();
260 16
            $this->addDataRow(array_shift($data));
261 16
            $this->addHeaderBorder();
262 16
            $this->table->setData($data, $x, $y);
263 8
        }
264 34
    }
265
266
    /**
267
     * Adds the rows to the output
268
     */
269 34
    protected function addRows() {
270 34
        $data = $this->table->getData();
271 34
        array_walk($data, [$this, 'addDataRow']);
272 34
    }
273
274
    /**
275
     * Adds the row with the specified data to the output
276
     * @param array $row
277
     * @return void
278
     */
279 34
    protected function addDataRow($row) {
280 34
        $this->addRow(
281 34
            $this->metadata['content']['left'],
282 34
            $this->metadata['content']['middle'],
283 34
            $this->metadata['content']['right'],
284 34
            $this->metadata['content']['pad'],
285 17
            $row
286 17
        );
287 34
    }
288
289
    /**
290
     * Adds the bottom border of the header to the output
291
     * @return void
292
     */
293 16
    protected function addHeaderBorder() {
294 16
        $this->addRow(
295 16
            $this->metadata['header']['left'],
296 16
            $this->metadata['header']['middle'],
297 16
            $this->metadata['header']['right'],
298 16
            $this->metadata['header']['pad']
299 8
        );
300 16
    }
301
302
    /**
303
     * Adds the bottom border to the output
304
     * @return void
305
     */
306 34
    protected function addBottomBorder() {
307 34
        if ($this->metadata['bottom_border']) {
308 30
            $this->addRow(
309 30
                $this->metadata['bottom_border']['left'],
310 30
                $this->metadata['bottom_border']['middle'],
311 30
                $this->metadata['bottom_border']['right'],
312 30
                $this->metadata['bottom_border']['pad']
313 15
            );
314 15
        }
315 34
    }
316
317
    /**
318
     * Adds the row to the output
319
     * @param string $lb
320
     * @param string $bm
321
     * @param string $br
322
     * @param string $pad
323
     * @param array $row
324
     * @return void
325
     */
326 34
    protected function addRow($lb, $bm, $br, $pad, $row = []) {
327 34
        $delimiter = $lb;
328 34
        for ($i = 0; $i < $this->table->getDimensionX(); $i++) {
329 34
            $maxLength = $this->table->getColumnsMaxLength($i);
330 34
            $this->output .= $delimiter;
331 34
            if (count($row)) {
332 34
                $cell = isset($row[$i]) ? $row[$i] : '';
333 34
                $spaces = str_repeat($pad, $maxLength - strlen($cell));
334 34
                $this->output .= " {$cell}{$spaces} ";
335 17
            } else {
336 32
                $this->output .= str_repeat($pad, $maxLength + 2);
337
            }
338 34
            $delimiter = $bm;
339 17
        }
340 34
        $this->output .= $br . PHP_EOL;
341 34
    }
342
343
}
344