Passed
Branch dev (8bd4f4)
by Michael
24:22
created

AdminPageFramework_Utility_InterpreterHTMLTable   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 46
eloc 183
dl 0
loc 300
rs 8.72
c 1
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A ___getRowsOfMultiColumns() 0 16 3
A ___getTableFooterOfKeyValuePair() 0 14 2
A ___getTableHeaderOfMultiColumns() 0 10 2
B ___getColumnValue() 0 27 7
A getTableOfKeyValues() 0 23 1
A ___getTableFooter() 0 7 3
A ___getHTMLEscaped() 0 2 2
A ___getTableRows() 0 7 3
A ___getTableCaption() 0 12 3
A ___getRowsOfKeyValuePair() 0 18 2
A ___getTableHeader() 0 7 3
A getTableOfArray() 0 24 1
A ___getList() 0 18 4
A ___getTableFooterOfMultiColumns() 0 10 2
A ___shouldKeyValuePair() 0 9 4
A ___getTableHeaderOfKeyValuePair() 0 14 2
A ___getColumns() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like AdminPageFramework_Utility_InterpreterHTMLTable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AdminPageFramework_Utility_InterpreterHTMLTable, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Admin Page Framework
4
 *
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2021, Michael Uno; Licensed MIT
7
 *
8
 */
9
10
/**
11
 * Provides utility methods which do not use WordPress functions.
12
 *
13
 * @since    3.9.0
14
 * @package  AdminPageFramework/Utility
15
 * @internal
16
 */
17
abstract class AdminPageFramework_Utility_InterpreterHTMLTable extends AdminPageFramework_Utility_HTMLAttribute {
18
19
    /**
20
     * Generates an HTML table from a given array.
21
     *
22
     * Similar to `getTableOfArray()` but this does not support multiple columns in a single row.
23
     * All rows consist of key-value pair, representing the array structure.
24
     *
25
     * @param  array   $aArray
26
     * @param  array   $aAllAttributes
27
     * @param  array   $aHeader
28
     * @param  array   $aFooter
29
     * @param  boolean $bEscape
30
     * @param  string  $sCaption
31
     * @return string
32
     * @since  3.9.0
33
     */
34
    static public function getTableOfKeyValues( array $aArray, array $aAllAttributes=array(), array $aHeader=array(), array $aFooter=array(), $bEscape=true, $sCaption='' ) {
35
        $_aAllAttributes = $aAllAttributes + array(
36
            'table'   => array(),
37
            'caption' => array(),
38
            'tbody'   => array(),
39
            'td'      => array(
40
                array(),
41
                array(),
42
            ),
43
            'tr'      => array(),
44
            't'       => array(),
45
            'ul'      => array(),
46
            'li'      => array(),
47
            'p'       => array(),
48
        );
49
        return "<table " . self::getAttributes( self::getElementAsArray( $_aAllAttributes, 'table' ) ) . ">"
50
                . self::___getTableCaption( $sCaption, $_aAllAttributes, $bEscape )
51
                . self::___getTableHeaderOfKeyValuePair( $aHeader, $aAllAttributes, $bEscape )
52
                . "<tbody " . self::getAttributes( self::getElementAsArray( $_aAllAttributes, 'tbody' ) ) . ">"
53
                    . self::___getRowsOfKeyValuePair( $aArray, $aAllAttributes, $bEscape )
54
                . "</tbody>"
55
                . self::___getTableFooterOfKeyValuePair( $aFooter, $aAllAttributes, $bEscape )
56
            . "</table>";
57
    }
58
59
    /**
60
     * Generates a table output of a given array.
61
     * Designed to display key-value pairs in a table.
62
     *
63
     * @param  array   $aArray           The data to display in a table.
64
     * @param  array   $aAllAttributes   A set of array representing tag attributes.
65
     * @param  array   $aHeader          Key value pairs of the table header. Only the first depth is supported.
66
     * @param  array   $aFooter          Key value pairs of the table footer. Only the first depth is supported.
67
     * @param  boolean $bEscape          Whether to escape values or not.
68
     * @param  string  $sCaption         The table caption.
69
     * @return string
70
     * @since  3.9.0
71
     */
72
    static public function getTableOfArray( array $aArray, array $aAllAttributes=array(), array $aHeader=array(), array $aFooter=array(), $bEscape=true, $sCaption='' ) {
73
74
        $_aAllAttributes = $aAllAttributes + array(
75
            'table'   => array(),
76
            'caption' => array(),
77
            'tbody'   => array(),
78
            'td'      => array(
79
                array(),
80
                array(),
81
            ),
82
            'tr'      => array(),
83
            't'       => array(),
84
            'ul'      => array(),
85
            'li'      => array(),
86
            'p'       => array(),
87
        );
88
        return "<table " . self::getAttributes( self::getElementAsArray( $_aAllAttributes, 'table' ) ) . ">"
89
                . self::___getTableCaption( $sCaption, $_aAllAttributes, $bEscape )
90
                . self::___getTableHeader( $aHeader, $_aAllAttributes, $bEscape )
91
                . "<tbody " . self::getAttributes( self::getElementAsArray( $_aAllAttributes, 'tbody' ) ) . ">"
92
                    . self::___getTableRows( $aArray, $_aAllAttributes, $bEscape )
93
                . "</tbody>"
94
                . self::___getTableFooter( $aFooter, $_aAllAttributes, $bEscape )
95
            . "</table>";
96
    }
97
        static private function ___getTableCaption( $sCaption, $aAllAttributes, $bEscape ) {
98
            $sCaption = ( string ) $sCaption;
99
            if ( ! strlen( $sCaption ) ) {
100
                return '';
101
            }
102
            $_aCapAttr = self::getElementAsArray( $aAllAttributes, 'caption' );
103
            $_sCaption = $bEscape
104
                ? htmlspecialchars( $sCaption )
105
                : $sCaption;
106
            return "<caption " . self::getAttributes( $_aCapAttr ) . ">"
107
                    . $_sCaption
108
                . "</caption>";
109
        }
110
        static private function ___getHTMLEscaped( $sOutput, $bEscape ) {
111
            return $bEscape ? htmlspecialchars( $sOutput ) : $sOutput;
112
        }
113
        static private function ___getTableHeader( array $aHeader, array $aAllAttributes, $bEscape ) {
114
            if ( empty( $aHeader ) ) {
115
                return '';
116
            }
117
            return self::isAssociative( $aHeader )
118
                ? self::___getTableHeaderOfKeyValuePair( $aHeader, $aAllAttributes, $bEscape )
119
                : self::___getTableHeaderOfMultiColumns( $aHeader, $aAllAttributes, $bEscape );
120
121
        }
122
            static private function ___getTableHeaderOfKeyValuePair( array $aHeader, array $aAllAttributes, $bEscape ) {
123
                $_aTRAttr  = self::getElementAsArray( $aAllAttributes, 'tr' );
124
                $_aTRAttr[ 'class' ] = self::getClassAttribute( 'key-value', self::getElement( $_aTRAttr, array( 'class' ), '' ) );
125
                $_aTHAttr  = self::getElementAsArray( $aAllAttributes, 'th' );
126
                $_aTHAttr1 = self::getElementAsArray( $aAllAttributes, array( 'th', 0 ) ) + $_aTHAttr;
127
                $_aTHAttr2 = self::getElementAsArray( $aAllAttributes, array( 'th', 1 ) ) + $_aTHAttr;
128
                $_sOutput = '';
129
                foreach( $aHeader as $_sKey => $_sValue ) {
130
                    $_sOutput .= "<tr " . self::getAttributes( $_aTRAttr ) . ">"
131
                            . "<th " . self::getAttributes( $_aTHAttr1 ) . ">" . self::___getHTMLEscaped( $_sKey, $bEscape ) . "</th>"
132
                            . "<th " . self::getAttributes( $_aTHAttr2 ) . ">" . self::___getHTMLEscaped( $_sValue, $bEscape ) . "</th>"
133
                        . "</tr>";
134
                }
135
                return "<thead>" . $_sOutput . "</thead>";
136
            }
137
            static private function ___getTableHeaderOfMultiColumns( array $aHeader, array $aAllAttributes, $bEscape ) {
138
                $_aTRAttr  = self::getElementAsArray( $aAllAttributes, 'tr' );
139
                $_aTHAttr  = self::getElementAsArray( $aAllAttributes, 'th' );
140
                $_sOutput  = "<tr " . self::getAttributes( $_aTRAttr ) . ">";
141
                foreach( array_values( $aHeader ) as $_iIndex => $_sColumnName ) {
142
                    $_aTHAttrNth  = self::getElementAsArray( $aAllAttributes, array( 'th', $_iIndex ) ) + $_aTHAttr;
143
                    $_sOutput    .= "<th " . self::getAttributes( $_aTHAttrNth ) . ">" . self::___getHTMLEscaped( ( string ) $_sColumnName, $bEscape ) . "</th>";
144
                }
145
                $_sOutput .= "</tr>";
146
                return "<thead>" . $_sOutput . "</thead>";
147
            }
148
        static private function ___getTableFooter( array $aFooter, array $aAllAttributes, $bEscape ) {
149
            if ( empty( $aFooter ) ) {
150
                return '';
151
            }
152
            return self::isAssociative( $aFooter )
153
                ? self::___getTableFooterOfKeyValuePair( $aFooter, $aAllAttributes, $bEscape )
154
                : self::___getTableFooterOfMultiColumns( $aFooter, $aAllAttributes, $bEscape );
155
        }
156
            static private function ___getTableFooterOfKeyValuePair( array $aFooter, array $aAllAttributes, $bEscape ) {
157
                $_aTRAttr  = self::getElementAsArray( $aAllAttributes, 'tr' );
158
                $_aTDAttr  = self::getElementAsArray( $aAllAttributes, 'td' );
159
                $_aTRAttr[ 'class' ] = self::getClassAttribute( 'key-value', self::getElement( $_aTRAttr, array( 'class' ), '' ) );
160
                $_aTDAttr1 = self::getElementAsArray( $aAllAttributes, array( 'td', 0 ) ) + $_aTDAttr;
161
                $_aTDAttr2 = self::getElementAsArray( $aAllAttributes, array( 'td', 1 ) ) + $_aTDAttr;
162
                $_sOutput = '';
163
                foreach( $aFooter as $_sKey => $_sValue ) {
164
                    $_sOutput = "<tr " . self::getAttributes( $_aTRAttr ) . ">"
165
                            . "<td " . self::getAttributes( $_aTDAttr1 ) . ">" . self::___getHTMLEscaped( $_sKey, $bEscape ) . "</td>"
166
                            . "<td " . self::getAttributes( $_aTDAttr2 ) . ">" . self::___getHTMLEscaped( $_sValue, $bEscape ) . "</td>"
167
                        . "</tr>";
168
                }
169
                return "<tfoot>" . $_sOutput . "</tfoot>";                
170
            }
171
            static private function ___getTableFooterOfMultiColumns( array $aFooter, array $aAllAttributes, $bEscape ) {
172
                $_aTRAttr  = self::getElementAsArray( $aAllAttributes, 'tr' );
173
                $_aTDAttr  = self::getElementAsArray( $aAllAttributes, 'td' );
174
                $_sOutput  = "<tr " . self::getAttributes( $_aTRAttr ) . ">";
175
                foreach( array_values( $aFooter ) as $_iIndex => $_sColumnName ) {
176
                    $_aTDAttrNth  = self::getElementAsArray( $aAllAttributes, array( 'td', $_iIndex ) ) + $_aTDAttr;
177
                    $_sOutput    .= "<td " . self::getAttributes( $_aTDAttrNth ) . ">" . self::___getHTMLEscaped( ( string ) $_sColumnName, $bEscape ) . "</td>";
178
                }
179
                $_sOutput .= "</tr>";
180
                return "<tfoot>" . $_sOutput . "</tfoot>";
181
            }            
182
        static private function ___getTableRows( array $aArray, array $aAllAttributes, $bEscape ) {
183
            if ( empty( $aArray ) ) {
184
                return '';
185
            }
186
            return self::___shouldKeyValuePair( $aArray )
187
                ? self::___getRowsOfKeyValuePair( $aArray, $aAllAttributes, $bEscape )
188
                : self::___getRowsOfMultiColumns( $aArray, $aAllAttributes, $bEscape );
189
        }
190
            static private function ___shouldKeyValuePair( array $aArray ) {
191
                if ( self::isAssociative( $aArray ) ) {
192
                    return true;
193
                }
194
                $_aFirstItem = self::getAsArray( self::getFirstElement( $aArray ) );
195
                if ( self::isAssociative( $_aFirstItem ) || self::isMultiDimensional( $_aFirstItem ) ) {
196
                    return true;
197
                }
198
                return false;
199
            }
200
201
            /**
202
             * @param  array   $aItem
203
             * @param  array   $aAllAttributes
204
             * @param  boolean $bEscape
205
             * @return string
206
             * @since  3.9.0
207
             */
208
            static private function ___getRowsOfKeyValuePair( array $aItem, array $aAllAttributes, $bEscape ) {
209
                $_aTRAttr                 = self::getElementAsArray( $aAllAttributes, 'tr' );
210
                $_aTRAttr[ 'class' ]      = self::getClassAttribute( 'key-value', self::getElement( $_aTRAttr, array( 'class' ), '' ) );
211
                $_aTDAttr                 = self::getElementAsArray( $aAllAttributes, 'td' );
212
                $_aTDAttr                 = array_filter( $_aTDAttr, 'is_scalar' );
213
                $_aPAttr                  = self::getElementAsArray( $aAllAttributes, array( 'p' ) );
214
                $_aTDAttrFirst            = self::getElementAsArray( $aAllAttributes, array( 'td', 0 ) ) + $_aTDAttr;
215
                $_aTDAttrFirst[ 'class' ] = self::getClassAttribute( 'column-key', self::getElement( $_aTDAttrFirst, array( 'class' ), '' ) );
216
                $_sOutput = '';
217
                foreach( $aItem as $_sColumnName => $_asValue ) {
218
                    $_sOutput .= "<tr " . self::getAttributes( $_aTRAttr ) . ">";
219
                    $_sOutput .= "<td " . self::getAttributes( $_aTDAttrFirst ) . ">"
220
                            . "<p " . self::getAttributes( $_aPAttr )  . ">" . self::___getHTMLEscaped( $_sColumnName, $bEscape ) . "</p>"
221
                         . "</td>";
222
                    $_sOutput .= self::___getColumnValue( $_asValue, $aAllAttributes, $bEscape, 1 );
223
                    $_sOutput .= "</tr>";
224
                }
225
                return $_sOutput;
226
            }
227
            /**
228
             * @return string
229
             * @since  3.9.0
230
             */
231
            static private function ___getRowsOfMultiColumns( array $aArray, array $aAllAttributes, $bEscape ) {
232
                $_aTRAttr = self::getElementAsArray( $aAllAttributes, 'tr' );
233
                $_sOutput = '';
234
                foreach( $aArray as $_iRowIndex => $_asValue ) {
235
                    if ( is_scalar( $_asValue ) ) {
236
                        $_sOutput .= "<tr " . self::getAttributes( $_aTRAttr ) . ">"
237
                                . self::___getColumnValue( $_asValue, $aAllAttributes, $bEscape, 0 )
238
                            . "</tr>";
239
                        continue;
240
                    }
241
                    $_aColumns = self::getAsArray( $_asValue );
242
                    $_sOutput .= "<tr " . self::getAttributes( $_aTRAttr ) . ">"
243
                            . self::___getColumns( $_aColumns, $aAllAttributes, $bEscape )
244
                        . "</tr>";
245
                }
246
                return $_sOutput;
247
            }
248
                static private function ___getColumns( array $aColumns, $aAllAttributes, $bEscape ) {
249
                    $_sOutput = '';
250
                    foreach( array_values( $aColumns ) as $_iIndex => $_asValue ) {
251
                        $_sOutput .= self::___getColumnValue( $_asValue, $aAllAttributes, $bEscape, $_iIndex );
252
                    }
253
                    return $_sOutput;
254
                }
255
256
            /**
257
             * @param  mixed   $mValue
258
             * @param  array   $aAllAttributes
259
             * @param  boolean $bEscape
260
             * @param  integer $iColumnIndex Zero-based column index
261
             * @return string
262
             * @since  3.9.0
263
             */
264
            static private function ___getColumnValue( $mValue, array $aAllAttributes, $bEscape, $iColumnIndex ) {
265
                $_aTDAttr    = self::getElementAsArray( $aAllAttributes, 'td' );
266
                $_aTDAttr    = array_filter( $_aTDAttr, 'is_scalar' );
267
                $_aTDAttrNth = self::getElementAsArray( $aAllAttributes, array( 'td', $iColumnIndex ) ) + $_aTDAttr;
268
                $_aTDAttrNth[ 'class' ] = self::getClassAttribute( 'column-value', self::getElement( $_aTDAttrNth, array( 'class' ), '' ) );
269
                if ( is_null( $mValue ) ) {
270
                    $mValue = '(null)';
271
                }
272
                $_aPAttr        = self::getElementAsArray( $aAllAttributes, 'p' );
273
                if ( is_scalar( $mValue ) ) {
274
                    return "<td " . self::getAttributes( $_aTDAttrNth ) . ">"
275
                        . "<p " . self::getAttributes( $_aPAttr )  . ">" . self::___getHTMLEscaped( $mValue, $bEscape ) . "</p>"
276
                       . "</td>";
277
                }
278
                if ( is_array( $mValue ) ) {
279
                    return self::isAssociativeArray( $mValue ) || self::isMultiDimensional( $mValue )
280
                        ? "<td " . self::getAttributes( $_aTDAttrNth ) . ">"
281
                            . self::getTableOfKeyValues( $mValue, $aAllAttributes )
282
                        . "</td>"
283
                        : "<td " . self::getAttributes( $_aTDAttrNth ) . ">"
284
                            // @todo may ought to be numeric-rows table
285
                            . self::___getList( $mValue, $aAllAttributes, $bEscape )
286
                        . "</td>";
287
                }
288
                return "<td " . self::getAttributes( $_aTDAttrNth ) . ">"
289
                        . '(' . gettype( $mValue ) . ')' . ( is_object( $mValue ) ? get_class( $mValue ) : '' )
290
                    . "</td>";
291
            }
292
                /**
293
                 * @param  array $aArray
294
                 * @param  array $aAllAttributes
295
                 * @param  boolean $bEscape
296
                 * @return string
297
                 * @since  3.9.0
298
                 */
299
                static private function ___getList( array $aArray, $aAllAttributes, $bEscape ) {
300
                    $_aULAttr = self::getElementAsArray( $aAllAttributes, 'ul' );
301
                    $_aLIAttr = self::getElementAsArray( $aAllAttributes, 'li' );
302
                    $_aULAttr[ 'class' ] = self::getClassAttribute( 'numeric', self::getElement( $_aULAttr, array( 'class' ), '' ) );
303
                    if ( empty( $aArray ) ) {
304
                        return '';
305
                    }
306
                    $_sList   = "<ul " . self::getAttributes( $_aULAttr ) . ">";
307
                    foreach( $aArray as $_asValue ) {
308
                        $_sItem  = is_array( $_asValue )
309
                            ? self::___getList( $_asValue, $aAllAttributes, $bEscape )
310
                            : self::___getHTMLEscaped( $_asValue, $bEscape );
311
                        $_sList .= "<li " . self::getAttributes( $_aLIAttr ) . ">"
312
                                . $_sItem
313
                            . "</li>";
314
                    }
315
                    $_sList  .= "</ul>";
316
                    return $_sList;
317
                }
318
319
}