Table   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 337
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 337
ccs 97
cts 97
cp 1
rs 9.36
c 0
b 0
f 0
wmc 38
lcom 1
cbo 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A setHeader() 0 4 1
A setRows() 0 4 1
A setAttributes() 0 4 1
A setCaption() 0 4 1
A themeTableHead() 0 8 2
A quick() 0 6 1
B render() 0 42 8
A prepareTableClasses() 0 21 5
B themeTableRow() 0 30 6
A themeTableCell() 0 22 4
A is_in_array() 0 10 3
A attributes() 0 19 4
1
<?php
2
/**
3
 * Generate a table
4
 */
5
namespace Rocket\UI\Table;
6
7
class Table
8
{
9
    /**
10
     * Holds all content rows
11
     *
12
     * @var array
13
     */
14
    protected $rows;
15
16
    /**
17
     * Holds all header cells
18
     *
19
     * @var array
20
     */
21
    protected $header;
22
23
    /**
24
     * Attributes for the table
25
     *
26
     * @var array
27
     */
28
    protected $attributes;
29
30
    /**
31
     * Table's caption
32
     *
33
     * @var string
34
     */
35
    protected $caption;
36
37
    /**
38
     * Prepare a table
39
     *
40
     * @param array|null $header
41
     * @param array|null $rows
42
     * @param array $attributes
43
     * @param string|null $caption
44
     */
45 63
    public function __construct($header = null, $rows = null, $attributes = [], $caption = null)
46
    {
47 63
        $this->setHeader($header);
0 ignored issues
show
Bug introduced by
It seems like $header defined by parameter $header on line 45 can also be of type null; however, Rocket\UI\Table\Table::setHeader() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
48 63
        $this->setRows($rows);
0 ignored issues
show
Bug introduced by
It seems like $rows defined by parameter $rows on line 45 can also be of type null; however, Rocket\UI\Table\Table::setRows() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
49 63
        $this->setAttributes($attributes);
50 63
        $this->setCaption($caption);
51 63
    }
52
53
    /**
54
     * Set the header
55
     *
56
     * @param array $header
57
     */
58 63
    public function setHeader(array $header)
59
    {
60 63
        $this->header = $header;
61 63
    }
62
63
    /**
64
     * Set the rows
65
     *
66
     * @param array $content
67
     */
68 63
    public function setRows(array $content)
69
    {
70 63
        $this->rows = $content;
71 63
    }
72
73
    /**
74
     * Set the attributes
75
     *
76
     * @param array $attributes
77
     */
78 63
    public function setAttributes(array $attributes)
79
    {
80 63
        $this->attributes = $attributes;
81 63
    }
82
83
    /**
84
     * Set the caption
85
     *
86
     * @param $caption
87
     */
88 63
    public function setCaption($caption)
89
    {
90 63
        $this->caption = $caption;
91 63
    }
92
93
    /**
94
     * Render the whole table
95
     *
96
     * @return string
97
     */
98 15
    public function render()
99
    {
100 15
        $has_header = count($this->header);
101 15
        $has_rows = count($this->rows);
102
103 15
        $this->prepareTableClasses($has_header);
104
105 15
        $output = '<table' . $this->attributes($this->attributes) . ">\n";
106
107 15
        if (isset($this->caption)) {
108 3
            $output .= '<caption>' . $this->caption . "</caption>\n";
109
        }
110
111
        // Format the table header:
112 15
        if ($has_header) {
113 9
            $output .= $this->themeTableHead($has_rows);
0 ignored issues
show
Documentation introduced by
$has_rows is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
114
        }
115
116 15
        $footer_rows = '';
117
118
        // Format the table rows:
119 15
        if ($has_rows) {
120 6
            $output .= "<tbody>\n";
121 6
            foreach ($this->rows as $row) {
122 6
                $rendered = $this->themeTableRow($row);
123 6
                if (array_key_exists('footer', $row) && $row['footer'] == true) {
124 3
                    $footer_rows .= $rendered;
125
                } else {
126 6
                    $output .= $rendered;
127
                }
128
            }
129 6
            $output .= "</tbody>\n";
130
        }
131
132 15
        if ($footer_rows != '') {
133 3
            $output .= "<tfoot>\n$footer_rows</tfoot>\n";
134
        }
135
136 15
        $output .= "</table>\n";
137
138 15
        return $output;
139
    }
140
141
    /**
142
     * Prepare the classes for the table
143
     *
144
     * @param $has_header
145
     */
146 27
    private function prepareTableClasses($has_header)
147
    {
148 27
        $default_classes = ['table'];
149
150 27
        if (!empty($this->attributes['class'])) {
151 6
            $items = explode(' ', $this->attributes['class']);
152 6
            $default_classes = array_merge($default_classes, $items);
153
        }
154
155
        //if no class starts with "table-" will add striped tables
156 27
        if (empty($this->attributes['class']) || !$this->is_in_array('/^table-/', $default_classes)) {
157 24
            $default_classes[] = 'table-striped';
158
        }
159
160
        // Add sticky headers, if applicable.
161 27
        if ($has_header) {
162 18
            $default_classes[] = 'sticky-enabled';
163
        }
164
165 27
        $this->attributes['class'] = implode(' ', $default_classes);
166 27
    }
167
168
    /**
169
     * Render the header
170
     *
171
     * @param bool $has_rows
172
     * @return string
173
     */
174 21
    private function themeTableHead($has_rows)
175
    {
176 21
        $output = $this->themeTableRow($this->header, true);
177
178
        // HTML requires that the thead tag has tr tags in it followed by tbody
179
        // tags. Using ternary operator to check and see if we have any rows.
180 21
        return $has_rows ? "<thead>\n{$output}</thead>" : $output;
181
    }
182
183
    /**
184
     * Render a complete row
185
     *
186
     * @param array $row
187
     * @param bool $header do we render th ?
188
     * @return string
189
     */
190 33
    private function themeTableRow($row, $header = false)
191
    {
192 33
        $attributes = [];
193 33
        $row_content = '';
194
195 33
        $cells = $row;
196
197
        // Check if we're dealing with a simple or complex row
198 33
        if (isset($row['data'])) {
199 9
            unset($row['footer']);
200 9
            foreach ($row as $key => $value) {
201 9
                if ($key == 'data') {
202 9
                    $cells = $value;
203
                } else {
204 6
                    $attributes[$key] = $value;
205
                }
206
            }
207
        }
208
209 33
        if (count($cells)) {
210
            // Build row
211 33
            $row_content .= '<tr' . $this->attributes($attributes) . '>';
212 33
            foreach ($cells as $cell) {
213 33
                $row_content .= $this->themeTableCell($cell, $header);
0 ignored issues
show
Documentation introduced by
$header is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
214
            }
215 33
            $row_content .= "</tr>\n";
216
        }
217
218 33
        return $row_content;
219
    }
220
221
    /**
222
     * Theme a single cell
223
     *
224
     * @param array $cell
225
     * @param string $header
226
     * @return string
227
     */
228 45
    private function themeTableCell($cell, $header = null)
229
    {
230 45
        $attributes = '';
231
232 45
        if (is_array($cell)) {
233 12
            $data = isset($cell['data']) ? $cell['data'] : '';
234 12
            $header |= isset($cell['header']);
235 12
            unset($cell['data']);
236 12
            unset($cell['header']);
237 12
            $attributes = $this->attributes($cell);
238
        } else {
239 39
            $data = $cell;
240
        }
241
242 45
        if ($header) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $header of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
243 24
            $output = "<th$attributes>$data</th>";
244
        } else {
245 27
            $output = "<td$attributes>$data</td>";
246
        }
247
248 45
        return $output;
249
    }
250
251
    /**
252
     * Return a themed table.
253
     *
254
     * @param $header array
255
     *   An array containing the table headers. Each element of the array can be
256
     *   either a localized string or an associative array with the following keys:
257
     *   - "data": The localized title of the table column.
258
     *   - "field": The database field represented in the table column (required if
259
     *     user is to be able to sort on this column).
260
     *   - "sort": A default sort order for this column ("asc" or "desc").
261
     *   - Any HTML attributes, such as "colspan", to apply to the column header cell.
262
     * @param $rows array
263
     *   An array of table rows. Every row is an array of cells, or an associative
264
     *   array with the following keys:
265
     *   - "data": an array of cells
266
     *   - Any HTML attributes, such as "class", to apply to the table row.
267
     *
268
     *   Each cell can be either a string or an associative array with the following keys:
269
     *   - "data": The string to display in the table cell.
270
     *   - "header": Indicates this cell is a header.
271
     *   - Any HTML attributes, such as "colspan", to apply to the table cell.
272
     *
273
     *   Here's an example for $rows:
274
     *   <code>
275
     *   $rows = array(
276
     *     // Simple row
277
     *     array(
278
     *       'Cell 1', 'Cell 2', 'Cell 3'
279
     *     ),
280
     *     // Row with attributes on the row and some of its cells.
281
     *     array(
282
     *       'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => 'funky'
283
     *     )
284
     *   );
285
     *   </code>
286
     *
287
     * @param $attributes array     An array of HTML attributes to apply to the table tag.
288
     * @param $caption string       A localized string to use for the <caption> tag.
289
     * @return string               An HTML string representing the table.
290
     */
291 15
    public static function quick($header, $rows, $attributes = [], $caption = null)
292
    {
293 15
        $table = new self($header, $rows, $attributes, $caption);
294
295 15
        return $table->render();
296
    }
297
298
    /**
299
     * is in array ? with a regex as needle
300
     *
301
     * @param string $pattern
302
     * @param array $subjectArray
303
     * @return bool
304
     */
305 6
    protected function is_in_array($pattern, array $subjectArray, &$allMatches = [], $flags = null, $offset = null)
0 ignored issues
show
Unused Code introduced by
The parameter $allMatches is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
306
    {
307 6
        foreach ($subjectArray as $subject) {
308 6
            if (preg_match($pattern, $subject, $matches, $flags, $offset)) {
309 3
                return true;
310
            }
311
        }
312
313 3
        return false;
314
    }
315
316
    /**
317
     * Build an HTML attribute string from an array.
318
     *
319
     * Taken form Illuminate/html, copied as it has far too much dependencies (13 !) and we only need these 10 lines
320
     *
321
     * @param array $attributes
322
     * @return string
323
     */
324 45
    protected function attributes($attributes)
325
    {
326 45
        $html = [];
327
328
        // For numeric keys we will assume that the key and the value are the same
329
        // as this will convert HTML attributes such as "required" to a correct
330
        // form like required="required" instead of using incorrect numerics.
331 45
        foreach ((array) $attributes as $key => $value) {
332
            //if (is_numeric($key)) { //should not happen
333
            //    $key = $value;
334
            //}
335
336 33
            if (!is_null($value)) {
337 33
                $html[] = $key . '="' . e($value) . '"';
338
            }
339
        }
340
341 45
        return count($html) > 0 ? ' ' . implode(' ', $html) : '';
342
    }
343
}
344