Completed
Push — version-4-wip ( 86a2b9...5c3ca2 )
by Craig
03:49
created

Table::getData()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 9.6666
c 0
b 0
f 0
cc 4
nc 5
nop 1
crap 4
1
<?php
2
3
namespace League\CLImate\TerminalObject\Basic;
4
5
use League\CLImate\Exceptions\InvalidArgumentException;
6
use League\CLImate\TerminalObject\Helper\StringLength;
7
use function get_object_vars;
8
use function is_array;
9
use function is_object;
10
11
class Table extends BasicTerminalObject
12
{
13
    use StringLength;
14
15
    /**
16
     * The data for the table, an array of (arrays|objects)
17
     *
18
     * @var array $data
19
     */
20
    protected $data           = [];
21
22
    /**
23
     * An array of the widths of each column in the table
24
     *
25
     * @var array $column_widths
26
     */
27
    protected $column_widths  = [];
28
29
    /**
30
     * The width of the table
31
     *
32
     * @var integer $table_width
33
     */
34
    protected $table_width    = 0;
35
36
    /**
37
     * The divider between table cells
38
     *
39
     * @var string $column_divider
40
     */
41
    protected $column_divider = ' | ';
42
43
    /**
44
     * The border to divide each row of the table
45
     *
46
     * @var string $border
47
     */
48
    protected $border;
49
50
    /**
51
     * The array of rows that will ultimately be returned
52
     *
53
     * @var array $rows
54
     */
55
    protected $rows           = [];
56
57
    /**
58
     * @var string $pregix A string to be output before each row is output.
59
     */
60
    private $prefix = "";
61
62
63 36
    public function __construct(array $data, $prefix = "")
64
    {
65 36
        $this->data = $this->getData($data);
66 32
        $this->prefix = $prefix;
67 32
    }
68
69
70
    /**
71
     * @param array $input
72
     *
73
     * @return array
74
     */
75 36
    private function getData(array $input)
76
    {
77 36
        $output = [];
78
79 36
        foreach ($input as $item) {
80 36
            if (is_object($item)) {
81 4
                $item = get_object_vars($item);
82
            }
83
84 36
            if (!is_array($item)) {
85 4
                throw new InvalidArgumentException("Invalid table data, you must pass an array of arrays or objects");
86
            }
87
88 32
            $output[] = $item;
89
        }
90
91 32
        return $output;
92
    }
93
94
95
    /**
96
     * Return the built rows
97
     *
98
     * @return array
99
     */
100 32
    public function result()
101
    {
102 32
        $this->column_widths = $this->getColumnWidths();
103 32
        $this->table_width   = $this->getWidth();
104 32
        $this->border        = $this->getBorder();
105
106 32
        $this->buildHeaderRow();
107
108 32
        foreach ($this->data as $columns) {
109 32
            $this->addLine($this->buildRow($columns));
110 32
            $this->addLine($this->border);
111
        }
112
113 32
        return $this->rows;
114
    }
115
116
    /**
117
     * Append a line to the output.
118
     *
119
     * @param string $line The line to output
120
     *
121
     * @return void
122
     */
123 32
    private function addLine($line)
124
    {
125 32
        $this->rows[] = $this->prefix . $line;
126 32
    }
127
128
129
    /**
130
     * Determine the width of the table
131
     *
132
     * @return integer
133
     */
134 32
    protected function getWidth()
135
    {
136 32
        $first_row = reset($this->data);
137 32
        $first_row = $this->buildRow($first_row);
138
139 32
        return $this->lengthWithoutTags($first_row);
140
    }
141
142
    /**
143
     * Get the border for each row based on the table width
144
     */
145 32
    protected function getBorder()
146
    {
147 32
        return (new Border())->length($this->table_width)->result();
148
    }
149
150
    /**
151
     * Check for a header row (if it's an array of associative arrays or objects),
152
     * if there is one, tack it onto the front of the rows array
153
     */
154 32
    protected function buildHeaderRow()
155
    {
156 32
        $this->addLine($this->border);
157
158 32
        $header_row = $this->getHeaderRow();
159 32
        if ($header_row) {
160 28
            $this->addLine($this->buildRow($header_row));
161 28
            $this->addLine((new Border)->char('=')->length($this->table_width)->result());
162
        }
163 32
    }
164
165
    /**
166
     * Get table row
167
     *
168
     * @param  mixed  $columns
169
     *
170
     * @return string
171
     */
172 32
    protected function buildRow($columns)
173
    {
174 32
        $row = [];
175
176 32
        foreach ($columns as $key => $column) {
177 32
            $row[] = $this->buildCell($key, $column);
178
        }
179
180 32
        $row = implode($this->column_divider, $row);
181
182 32
        return trim($this->column_divider . $row . $this->column_divider);
183
    }
184
185
    /**
186
     * Build the string for this particular table cell
187
     *
188
     * @param  mixed  $key
189
     * @param  string $column
190
     *
191
     * @return string
192
     */
193 32
    protected function buildCell($key, $column)
194
    {
195 32
        return  $this->pad($column, $this->column_widths[$key]);
196
    }
197
198
    /**
199
     * Get the header row for the table if it's an associative array or object
200
     *
201
     * @return mixed
202
     */
203 32
    protected function getHeaderRow()
204
    {
205 32
        $first_item = reset($this->data);
206
207 32
        $keys       = array_keys($first_item);
208 32
        $first_key  = reset($keys);
209
210
        // We have an associative array (probably), let's have a header row
211 32
        if (!is_int($first_key)) {
212 28
            return array_combine($keys, $keys);
213
        }
214
215 4
        return false;
216
    }
217
218
    /**
219
     * Determine the width of each column
220
     *
221
     * @return array
222
     */
223 32
    protected function getColumnWidths()
224
    {
225 32
        $first_row = reset($this->data);
226
227
        // Create an array with the columns as keys and values of zero
228 32
        $column_widths = $this->getDefaultColumnWidths($first_row);
229
230 32
        foreach ($this->data as $columns) {
231 32
            foreach ($columns as $key => $column) {
232 32
                $column_widths[$key] = $this->getCellWidth($column_widths[$key], $column);
233
            }
234
        }
235
236 32
        return $column_widths;
237
    }
238
239
    /**
240
     * Set up an array of default column widths
241
     *
242
     * @param array $columns
243
     *
244
     * @return array
245
     */
246 32
    protected function getDefaultColumnWidths(array $columns)
247
    {
248 32
        $widths = $this->arrayOfStrLens(array_keys($columns));
249
250 32
        return array_combine(array_keys($columns), $widths);
251
    }
252
253
    /**
254
     * Determine the width of the columns without tags
255
     *
256
     * @param array  $current_width
257
     * @param string $str
258
     *
259
     * @return integer
260
     */
261 32
    protected function getCellWidth($current_width, $str)
262
    {
263 32
        return max($current_width, $this->lengthWithoutTags($str));
264
    }
265
}
266