Completed
Push — master ( 360629...31e4ac )
by Gunnar
02:50
created

CHTMLTable::isObjectSpecifiedAsKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
crap 2
1
<?php
2
namespace Guer\HTMLTable;
3
4
/**
5
 * Class that generates a table in HTML with table data from an array of objects.
6
 *
7
 * Through a table specification array it is possible to set an CSS id or
8
 * a class for the table and a caption.
9
 *
10
 * Through a column specification it is possible to set the column title, set
11
 * a colspan for the table cell and footer cell, through type determine if the
12
 * row of cells belongs to the table body or table foot and through a function
13
 * include advanced settings for a column.
14
 *
15
 * @author Gunnar Eriksson <[email protected]>
16
 */
17
class CHTMLTable
18
{
19
    const FOOTER = 'footer';
20
21
    private $tableSpec;
22
    private $tableHead;
23
    private $tableBody;
24
    private $tableFoot;
25
26
    /**
27
     * Constructor
28
     *
29
     * Creates a table with table head, table body and if specified, a table
30
     * footer. It is possible to specify the table and the tabel cells settings
31
     * per column.
32
     *
33
     * @param string[] $tableSpecs  table settings.
34
     * @param mixed[] $data         table cell data.
35
     * @param mixed[] $columnSpecs  table columns cell settings.
36
     */
37 11
    public function __construct($tableSpecs = [], $data = [], $columnSpecs = [])
38
    {
39 11
        $this->create($tableSpecs, $data, $columnSpecs);
40 11
    }
41
42
    /**
43
     * Creates a table with cell data.
44
     *
45
     * Creates a table with table head, table body with table data and if
46
     * specified, a table footer. It is possible to specify the table and the
47
     * tabel cells settings per column.
48
     *
49
     * @param string[] $tableSpecs  table settings.
50
     * @param mixed[] $data         table cell data.
51
     * @param mixed[] $columnSpecs  table columns cell settings.
52
     *
53
     * @return object the html table object.
54
     */
55 11
    public function create($tableSpecs = [], $data = [], $columnSpecs = [])
56
    {
57 11
        $this->resetTableTags();
58 11
        $this->setTableSpecifications($tableSpecs);
59
60 11
        $this->createTableHead($data, $columnSpecs);
61 11
        $this->createTableBody($data, $columnSpecs);
62 11
        $this->createTableFooter($columnSpecs);
63
64 11
        return $this;
65
    }
66
67
    /**
68
     * Helper method to reset main parts of table tags.
69
     *
70
     * Sets the table head, table body and table foot tag to null.
71
     *
72
     * @return void
73
     */
74 11
    private function resetTableTags()
75
    {
76 11
        $this->tableHead = null;
77 11
        $this->tableBody = null;
78 11
        $this->tableFoot = null;
79 11
    }
80
81
    /**
82
     * Helper method to set the table specifications.
83
     *
84
     * Merges the table specifications with the default specifications.
85
     * Default table CSS id is html-table.
86
     *
87
     * @param  string[] $tableSpec the table specification.
88
     *
89
     * @return void
90
     */
91 11
    private function setTableSpecifications($tableSpec)
92
    {
93
        $defaults = [
94
            // Always have a id for the form
95 11
            'id' => 'html-table',
96 11
        ];
97
98 11
        if ($this->isClassPresent($tableSpec)) {
99 1
            $tableSpec = $this->removeId($tableSpec);
100 1
        }
101
102 11
        $this->tableSpec = array_merge($defaults, $tableSpec);
103 11
    }
104
105
    /**
106
     * Helper method to check if a CSS class tag is present
107
     *
108
     * Checks if a CSS class tag is present in the table specification.
109
     *
110
     * @param  string[] $tableSpec the table specification.
111
     *
112
     * @return boolean  true if class is present in the table specification,
113
     *                  false otherwise.
114
     */
115 11
    private function isClassPresent($tableSpec)
116
    {
117 11
        return isset($tableSpec['class']) ? true : false;
118
    }
119
120
    /**
121
     * Helper method to reset the id tag.
122
     *
123
     * Sets the CSS id tag to null.
124
     *
125
     * @param  string[] $tableSpec the table specification.
126
     *
127
     * @return string[] the table specification without the CSS id tag.
128
     */
129 1
    private function removeId($tableSpec) {
130 1
        $tableSpec['id'] = null;
131
132 1
        return $tableSpec;
133
    }
134
135
    /**
136
     * Helper method to create the table head.
137
     *
138
     * Creates the table head. The title of the columns are set according to
139
     * the table tag in the column specifications. Otherwise, the title is set
140
     * to the keys name in the table cell data array.
141
     *
142
     * @param  mixed[]  $data        table cell data.
143
     * @param  mixed[]  $columnSpecs table columns cell settings.
144
     *
145
     * @return void
146
     */
147 11
    private function createTableHead($data, $columnSpecs)
148
    {
149 11
        $this->tableHead = "\n<thead>";
150 11
        $this->tableHead .= "\n<tr>";
151
152 11
        if (empty($columnSpecs))
153 11
        {
154 11
            $this->setColumnTitlesFromData($data);
155 11
        } else {
156 7
            $this->setColumnTitlesFromColumnSpecifications($columnSpecs);
157
        }
158
159 11
        $this->tableHead .= "\n</tr>";
160 11
        $this->tableHead .= "\n</thead>";
161 11
    }
162
163
    /**
164
     * Helper method to set the column titles from the data array.
165
     *
166
     * Uses the first row in the table cell data array to set the titles of
167
     * the columns. The name of the columns are the key name for the objects in
168
     * the array containing data for the table.
169
     *
170
     * @param  mixed[]  $data   table cell data.
171
     *
172
     * @return void
173
     */
174 11
    private function setColumnTitlesFromData($data)
175
    {
176 11
        $firstRow = isset($data[0]) ? $data[0] : [];
177 11
        foreach ($firstRow as $key => $value) {
178 4
            $this->tableHead .= "\n<th>";
179 4
            $this->tableHead .= $key;
180 4
            $this->tableHead .= "</th>";
181 11
        }
182 11
    }
183
184
    /**
185
     * Helper method to set the column titles from column specifications.
186
     *
187
     * Uses column specifications to set the name of the columns in the table
188
     * head.
189
     *
190
     * @param  mixed[]  $columnSpecs    table columns cell settings
191
     *
192
     * @return void
193
     */
194 7
    private function setColumnTitlesFromColumnSpecifications($columnSpecs)
195
    {
196 7
        foreach ($columnSpecs as $key => $columnSpec) {
197 7
            if (!$this->isTableFooter($columnSpec)) {
198 7
                $this->tableHead .= "\n<th>";
199 7
                $this->tableHead .= $this->getTitle($key, $columnSpec);
0 ignored issues
show
Documentation introduced by
$key is of type integer, but the function expects a array<integer,string>.

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...
200 7
                $this->tableHead .= "</th>";
201 7
            }
202 7
        }
203 7
    }
204
205
    /**
206
     * Helper method to check if the column cell belongs to the footer.
207
     *
208
     * Checks the type tag, in the column specification for one column, if the
209
     * tag is present and set to footer.
210
     *
211
     * @param  mixed[]  $columnSpec cell settings for one column.
212
     *
213
     * @return boolean true if the cell type belongs to the footer, false otherwise.
214
     */
215 7
    private function isTableFooter($columnSpec)
216
    {
217 7
        $isFooter = false;
218 7
        if (isset($columnSpec['type'])) {
219 2
            if (strcmp($columnSpec['type'], self::FOOTER) === 0) {
220 2
                $isFooter = true;
221 2
            }
222 2
        }
223
224 7
        return $isFooter;
225
    }
226
227
    /**
228
     * Helper method to get title from a column specification, if specified.
229
     *
230
     * Uses the title tag in the column specification for one column to get
231
     * the title. If the title tag is not set, the title is the key for the
232
     * objects int the array containing data for the table.
233
     *
234
     * @param  array<integer,string>    $key        the name of the key for the
235
     *                                              table cell data.
236
     * @param  mixed[]                  $columnSpec cell settings for one column.
237
     *
238
     * @return string[] the name from the title tag in the cell specification.
239
     *                  Otherwise, the table cell data key name.
240
     */
241 7
    private function getTitle($key, $columnSpec)
242
    {
243 7
        return isset($columnSpec['title']) ? $columnSpec['title'] : $key;
244
    }
245
246
    /**
247
     * Helper method to create the table body with table cell data.
248
     *
249
     * Sets the table cell data in the table body.
250
     *
251
     * @param  mixed[] $data        table cell data.
252
     * @param  mixed[] $columnSpecs table columns cell settings.
253
     *
254
     * @return void
255
     */
256 11
    private function createTableBody($data, $columnSpecs)
257
    {
258 11
        $this->setTableData($data, $columnSpecs);
259 11
        if (isset($this->tableBody)) {
260 11
            $this->tableBody = "\n<tbody>" . $this->tableBody . "\n</tbody>";
261 11
        }
262 11
    }
263
264
    /**
265
     * Helper method to set table data in table body.
266
     *
267
     * Sets table data according to the column specifications, if it is
268
     * specified. Otherwise it sets the data as it is stored in the data array.
269
     *
270
     * @param  mixed[] $data        table cell data.
271
     * @param  mixed[] $columnSpecs table columns cell settings.
272
     *
273
     * @return void
274
     */
275 11
    private function setTableData($data, $columnSpecs)
276
    {
277 11
        if (empty($columnSpecs)) {
278 11
            $this->setTableDataFromData($data);
279 11
        } else {
280 7
            $this->setTableDataAsSpecified($data, $columnSpecs);
281
        }
282 11
    }
283
284
    /**
285
     * Helper method to set table data from the data array.
286
     *
287
     * Sets table data from the data array.
288
     *
289
     * @param  mixed[]  $data   table cell data.
290
     *
291
     * @return void
292
     */
293 11
    private function setTableDataFromData($data)
294
    {
295 11
        foreach ($data as $row) {
296 4
            $this->tableBody .= "\n<tr>";
297 4
            foreach ($row as $value) {
298 4
                $this->tableBody .= "\n<td>";
299 4
                $this->tableBody .= $value;
300 4
                $this->tableBody .= "</td>";
301 4
            }
302 4
            $this->tableBody .= "\n</tr>";
303 11
        }
304 11
    }
305
306
    /**
307
     * Helper method to set table data according to the column specifications.
308
     *
309
     * Sets the table data according to the column specifications, if the cell
310
     * does not belong to the footer. Adds a colspan tag, if it is specified
311
     * for the cell in the column.
312
     *
313
     * @param  mixed[] $data         table cell data.
314
     * @param  mixed[] $columnSpecs  table columns cell settings.
315
     *
316
     * @return void
317
     */
318 7
    private function setTableDataAsSpecified($data, $columnSpecs)
319
    {
320 7
        foreach ($data as $row) {
321 7
            $this->tableBody .= "\n<tr>";
322 7
            foreach ($columnSpecs as $key => $columnSpec) {
323 7 View Code Duplication
                if (!$this->isTableFooter($columnSpec)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
324 7
                    $colspan = $this->getColspan($columnSpec);
325 7
                    $this->tableBody .= "\n<td{$colspan}>";
326 7
                    $this->tableBody .= $this->getValue($row, $key, $columnSpec);
327 7
                    $this->tableBody .= "</td>";
328 7
                }
329 7
            }
330 7
            $this->tableBody .= "\n</tr>";
331 7
        }
332 7
    }
333
334
    /**
335
     * Helper method to get the colspan value, if specified in the column
336
     * specification for the cell.
337
     *
338
     * @param  mixed[]  $columnSpec cell settings for one column.
339
     *
340
     * @return int the colspan value if specified. Otherwise null.
341
     */
342 7
    private function getColspan($columnSpec)
343
    {
344 7
        return isset($columnSpec['colspan']) ? " colspan='{$columnSpec['colspan']}'" : null;
345
    }
346
347
    /**
348
     * Helper method to get the value for a specific position in one row in
349
     * the data array.
350
     *
351
     * Gets the data from a specific position in one row in the data array.
352
     * If a function is specified for the cell in the column, the data is
353
     * runned through the function before it is returned.If the object key is
354
     * specified to object, the reference to the object is fetched from the
355
     * array of objects.
356
     *
357
     * @param  object   $row        one row of in the array of table data.
358
     * @param  string   $key        the name of the key in the associative data array.
359
     * @param  mixed[]  $columnSpec cell settings for one column.
360
     */
361 7
    private function getValue($row, $key, $columnSpec)
362
    {
363 7
        if ($this->isFunctionSpecified($columnSpec)) {
364 3
            if ($this->isObjectSpecifiedAsKey($key)) {
365 1
                $dataValue = isset($row) ? $row : "";
366 1
            } else {
367 2
                $dataValue = isset($row->$key) ? $row->$key : "";
368
            }
369
370 3
            return $this->getValueThroughFunction($columnSpec, $dataValue);
371
        } else {
372 7
            return isset($row->$key) ? $row->$key : "";
373
        }
374
    }
375
376
    /**
377
     * Helper method t check if the function tag is specified for the cells in
378
     * one column.
379
     *
380
     * Checks if the function tag is set for the cell in one column.
381
     *
382
     * @param  mixed[]  $columnSpec     cell settings for one column.
383
     *
384
     * @return boolean true if a function is connected to the cell, false otherwise.
385
     */
386 7
    private function isFunctionSpecified($columnSpec)
387
    {
388 7
        return isset($columnSpec['function']) ? true : false;
389
    }
390
391
    /**
392
     * Helper method to check if the object key is specified to object.
393
     *
394
     * Checks if the object key starts with object. The check is case insensitive.
395
     *
396
     * @param  string  $key the name of the key for the object.
397
     *
398
     * @return boolean true if the key starts with object, false otherwise.
399
     */
400 3
    private function isObjectSpecifiedAsKey($key)
401
    {
402 3
        $keyRest = substr($key, 0, 6);
403
404 3
        return strcasecmp($keyRest, "object") === 0 ? true : false;
405
    }
406
407
    /**
408
     * Helper method to run the value through a function before it is returned.
409
     *
410
     * Runs the value through a function, if a function is connected to the cell
411
     * in the column. If not function is connected to the cell through the
412
     * column specification, the value is returned as it is.
413
     *
414
     * @param mixed[]   $columnSpec     cell settings for one column
415
     * @param mixed     $dataValue      the value to run through function, if specified.
416
     *
417
     * @return the value.
418
     */
419 3
    private function getValueThroughFunction($columnSpec, $dataValue)
420
    {
421 3
        if (!empty($columnSpec['function'])) {
422 2
            return call_user_func($columnSpec['function'], $dataValue);
423
        } else {
424 1
            return $dataValue;
425
        }
426
    }
427
428
    /**
429
     * Helper method to create table footer with data.
430
     *
431
     * Creates table footer if the cell settings for the column is set to
432
     * footer in the column specifications.
433
     * Adds a colspan tag, if it is specified for the cell in the column.
434
     *
435
     * @param  mixed[] $columnSpecs table columns cell settings.
436
     *
437
     * @return void
438
     */
439 11
    private function createTableFooter($columnSpecs)
440
    {
441 11
        foreach ($columnSpecs as $columnSpec) {
442 7 View Code Duplication
            if ($this->isTableFooter($columnSpec)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
443 2
                $colspan = $this->getColspan($columnSpec);
444 2
                $this->tableFoot .= "\n<td{$colspan}>";
445 2
                $this->tableFoot .= $this->getFooterData($columnSpec);
446 2
                $this->tableFoot .= "</td>";
447 2
            }
448 11
        }
449
450 11
        if (isset($this->tableFoot)) {
451 2
            $this->tableFoot = "\n<tfoot>\n<tr>" . $this->tableFoot . "\n</tr>\n</tfoot>";
452 2
        }
453 11
    }
454
455
    /**
456
     * Helper method to get table footer data.
457
     *
458
     * Gets table footer data from the column specification. Checks if the
459
     * value should be fetched from a function or from the value tag.
460
     * If either the function or the value specified, an empty string is
461
     * returned.
462
     *
463
     * @param  mixed[] $columnSpec  cell settings for one column.
464
     *
465
     * @return mixed    the cell data value.
466
     */
467 2
    private function getFooterData($columnSpec)
468
    {
469 2
        if ($this->isFunctionSpecified($columnSpec)) {
470 1
            return call_user_func($columnSpec['function']);
471
        } else {
472 1
            return isset($columnSpec['value']) ? $columnSpec['value'] : "";
473
        }
474
    }
475
476
    /**
477
     * Gets the table.
478
     *
479
     * Gets the table with table data.
480
     *
481
     * @return html     the table with table data.
482
     */
483 11
    public function getHTMLTable()
484
    {
485 11
        $id = isset($this->tableSpec['id']) ? " id='{$this->tableSpec['id']}'" : null;
486 11
        $class = isset($this->tableSpec['class']) ? " class='{$this->tableSpec['class']}'" : null;
487 11
        $caption = isset($this->tableSpec['caption']) ? "<caption>{$this->tableSpec['caption']}</caption>" : null;
488
489 11
        $htmlTable = "<table{$id}{$class}>";
490 11
        $htmlTable .= $caption;
491 11
        $htmlTable .= $this->tableHead;
492 11
        $htmlTable .= $this->tableBody;
493 11
        $htmlTable .= $this->tableFoot;
494 11
        $htmlTable .= "\n</table>";
495
496 11
        return $htmlTable;
497
    }
498
}
499