Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 127
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
CargoDynamicTableFormat
0.00% covered (danger)
0.00%
0 / 127
0.00% covered (danger)
0.00%
0 / 2
2070
0.00% covered (danger)
0.00%
0 / 1
 allowedParameters
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 display
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 1
1980
1<?php
2/**
3 * Defines a "dynamic table" format, that displays query results in a
4 * JavaScript-based table that has sorting, pagination and searching, using
5 * the DataTables JS library.
6 *
7 * @author Yaron Koren
8 * @ingroup Cargo
9 */
10
11use MediaWiki\Html\Html;
12
13class CargoDynamicTableFormat extends CargoDisplayFormat {
14
15    public static function allowedParameters() {
16        return [
17            'rows per page' => [ 'type' => 'int' ],
18            'details fields' => [ 'type' => 'string' ],
19            'hidden fields' => [ 'type' => 'string' ],
20            'column widths' => [ 'type' => 'string' ],
21            'header tooltips' => [ 'type' => 'string' ]
22        ];
23    }
24
25    /**
26     * @param array $valuesTable Unused
27     * @param array $formattedValuesTable
28     * @param array $fieldDescriptions
29     * @param array $displayParams Unused
30     * @return string HTML
31     */
32    public function display( $valuesTable, $formattedValuesTable, $fieldDescriptions, $displayParams ) {
33        $this->mOutput->addModules( [ 'ext.cargo.datatables' ] );
34
35        $tableAttrs = [
36            'class' => 'cargoDynamicTable display',
37            'cellspacing' => '0',
38            'width' => '100%',
39            'data-mw-cargo-dynamic-table' => true,
40        ];
41
42        $detailsFields = [];
43        if ( array_key_exists( 'details fields', $displayParams ) && !empty( $displayParams[ 'details fields' ] ) ) {
44            $detailsFields = explode( ',', $displayParams['details fields'] );
45            // The field names in the $fieldDescriptions lack table names, and they
46            // have spaces instead of underscores. Since we need to compare these
47            // values to those, get the $detailsFields values in the same format.
48            foreach ( $detailsFields as &$detailsField ) {
49                $locOfDot = strpos( $detailsField, '.' );
50                if ( $locOfDot !== false ) {
51                    $detailsField = substr( $detailsField, $locOfDot + 1 );
52                }
53                $detailsField = trim( $detailsField );
54                if ( strpos( $detailsField, '_' ) > 0 ) {
55                    $detailsField = str_replace( '_', ' ', $detailsField );
56                }
57            }
58            $tableAttrs['data-mw-details-fields'] = "1";
59        }
60        // Special handlng for ordering.
61        $dataTableOrderByParams = [];
62        if ( array_key_exists( 'order by', $displayParams ) ) {
63            $orderByClauses = explode( ',', $displayParams['order by'] );
64            foreach ( $orderByClauses as $orderByClause ) {
65                $orderByClause = strtolower( trim( $orderByClause ) );
66                $sortAscending = true;
67                if ( substr( $orderByClause, -4 ) === ' asc' ) {
68                    $orderByClause = trim( substr( $orderByClause, 0, -3 ) );
69                } elseif ( substr( $orderByClause, -5 ) === ' desc' ) {
70                    $sortAscending = false;
71                    $orderByClause = trim( substr( $orderByClause, 0, -4 ) );
72                }
73                if ( $detailsFields ) {
74                    $i = 1;
75                } else {
76                    $i = 0;
77                }
78                foreach ( $fieldDescriptions as $fieldName => $fieldDescription ) {
79                    if ( in_array( $fieldName, $detailsFields ) ) {
80                        continue;
81                    }
82                    $fieldName = strtolower( str_replace( ' ', '_', $fieldName ) );
83                    if ( $orderByClause == $fieldName ) {
84                        $dataTableOrderByParams[] = [ $i, $sortAscending ? 'asc' : 'desc' ];
85                    }
86                    $i++;
87                }
88            }
89        }
90        // We have to set the text in this awkward way,
91        // instead of using the Html class, because it
92        // has to be displayed in a very specific way -
93        // single quotes outside, double quotes inside -
94        // for the jQuery part to work, and the Html
95        // class won't do it that way.
96        $tableAttrs['data-order'] = json_encode( $dataTableOrderByParams );
97
98        if ( array_key_exists( 'rows per page', $displayParams ) && $displayParams['rows per page'] != '' ) {
99            $tableAttrs['data-mw-page-length'] = $displayParams['rows per page'];
100        }
101        $text = '';
102        if ( array_key_exists( 'column widths', $displayParams ) ) {
103            if ( trim( $displayParams['column widths'] ) != '' ) {
104                $tableAttrs['data-mw-widths'] = $displayParams['column widths'];
105            }
106        }
107        if ( array_key_exists( 'header tooltips', $displayParams ) ) {
108            if ( trim( $displayParams['header tooltips'] ) != '' ) {
109                $tableAttrs['data-mw-tooltips'] = $displayParams['header tooltips'];
110            }
111        }
112        if ( array_key_exists( 'hidden fields', $displayParams ) ) {
113            $hiddenFields = array_map( 'trim', explode( ',', $displayParams['hidden fields'] ) );
114            $text .= wfMessage( 'cargo-dynamictables-togglecolumns' )->escaped() . ' ';
115            $matchFound = 0;
116            foreach ( $hiddenFields as $hiddenField ) {
117                if ( $detailsFields ) {
118                    $fieldNum = 1;
119                } else {
120                    $fieldNum = 0;
121                }
122                foreach ( $fieldDescriptions as $fieldName => $fieldDescription ) {
123                    if ( in_array( $fieldName, $detailsFields ) ) {
124                        continue;
125                    }
126                    if ( $hiddenField == $fieldName ) {
127                        if ( $matchFound++ > 0 ) {
128                            $text .= ' - ';
129                        }
130                        $text .= Html::element( 'a', [
131                            'class' => 'toggle-vis',
132                            'data-column' => $fieldNum,
133                        ], $hiddenField );
134                        break;
135                    }
136                    $fieldNum++;
137                }
138            }
139        }
140        $searchableColumns = false;
141        if ( array_key_exists( 'searchable columns', $displayParams ) ) {
142            $searchableColumns = strtolower( $displayParams['searchable columns'] ) == 'yes';
143        }
144        $tableContents = '<thead><tr>';
145        if ( $detailsFields ) {
146            $tableContents .= Html::rawElement( 'th', [ 'class' => 'details-control' ] );
147        }
148        foreach ( $fieldDescriptions as $fieldName => $fieldDescription ) {
149            if ( in_array( $fieldName, $detailsFields ) ) {
150                continue;
151            }
152            if ( strpos( $fieldName, 'Blank value ' ) === false ) {
153                $tableContents .= "\t\t\t\t" . Html::element( 'th', [], $fieldName );
154            } else {
155                $tableContents .= "\t\t\t\t" . Html::element( 'th' );
156            }
157        }
158
159        $tableContents .= '</tr></thead><tfoot><tr>';
160
161        if ( $detailsFields ) {
162            $tableContents .= Html::rawElement( 'th', [ 'class' => 'details-control' ] );
163        }
164        foreach ( $fieldDescriptions as $fieldName => $fieldDescription ) {
165            if ( in_array( $fieldName, $detailsFields ) ) {
166                continue;
167            }
168            if ( $searchableColumns ) {
169                $placeholder = wfMessage( 'cargo-dynamictables-searchcolumn', $fieldName )->escaped();
170                $attribs = [ 'data-mw-placeholder' => $placeholder ];
171            } else {
172                $attribs = null;
173            }
174            if ( strpos( $fieldName, 'Blank value ' ) === false ) {
175                $tableContents .= "\t\t\t\t" . Html::element( 'th', $attribs, $fieldName );
176            } else {
177                $tableContents .= "\t\t\t\t" . Html::element( 'th', $attribs, null );
178            }
179        }
180
181        $tableContents .= '</tr></tfoot><tbody>';
182
183        foreach ( $formattedValuesTable as $rowNum => $row ) {
184            if ( $detailsFields ) {
185                $tableData = Html::rawElement( 'td', [ 'class' => 'details-control' ], null );
186            } else {
187                $tableData = '';
188            }
189            $details = '';
190            foreach ( $fieldDescriptions as $field => $fieldDescription ) {
191                $attribs = null;
192                $value = null;
193
194                if ( array_key_exists( $field, $row ) ) {
195                    $value = $row[$field];
196                    if ( $fieldDescription->isDateOrDatetime() ) {
197                        $attribs = [ 'data-order' => $valuesTable[$rowNum][$field] ];
198                    }
199                }
200
201                if ( in_array( $field, $detailsFields ) ) {
202                    $detailsText = "\t\t\t\t" . Html::rawElement( 'td', $attribs, "<strong>$field: </strong>" );
203                    $detailsText .= "\t\t\t\t" . Html::rawElement( 'td', $attribs, $value );
204                    $details .= "\t\t\t" . Html::rawElement( 'tr', $attribs, $detailsText );
205                } else {
206                    $tableData .= "\t\t\t\t" . Html::rawElement( 'td', $attribs, $value );
207                }
208            }
209            $detailsTable =
210                Html::rawElement( 'table', [ 'border' => '0', 'cellspacing' => '0' ],
211                    Html::rawElement( 'tbody', [], $details ) );
212
213            $tableContents .= Html::rawElement( 'tr', [ 'data-mw-details' => $detailsTable ],
214                $tableData );
215        }
216
217        $tableContents .= '</tbody>';
218
219        $text .= Html::rawElement( 'table', $tableAttrs, $tableContents );
220
221        return $text;
222    }
223
224}