Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 123 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
CargoPageValues | |
0.00% |
0 / 123 |
|
0.00% |
0 / 8 |
1406 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 58 |
|
0.00% |
0 / 1 |
240 | |||
getTableLink | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getInfoForAllFields | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
getRowsForPageInTable | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
42 | |||
printRow | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
printTable | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
isListed | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Displays an interface to let users recreate data via the Cargo |
4 | * extension. |
5 | * |
6 | * @author Yaron Koren |
7 | * @ingroup Cargo |
8 | */ |
9 | |
10 | class CargoPageValues extends IncludableSpecialPage { |
11 | public $mTitle; |
12 | |
13 | public function __construct( $title = null ) { |
14 | parent::__construct( 'PageValues' ); |
15 | |
16 | $this->mTitle = $title; |
17 | } |
18 | |
19 | public function execute( $subpage = null ) { |
20 | if ( $subpage ) { |
21 | // Allow inclusion with e.g. {{Special:PageValues/Book}} |
22 | $this->mTitle = Title::newFromText( $subpage ); |
23 | } |
24 | |
25 | // If no title, or a nonexistent title, was set, just exit out. |
26 | // @TODO - display an error message. |
27 | if ( $this->mTitle == null || !$this->mTitle->exists() ) { |
28 | return true; |
29 | } |
30 | |
31 | $out = $this->getOutput(); |
32 | |
33 | $this->setHeaders(); |
34 | |
35 | $pageName = $this->mTitle->getPrefixedText(); |
36 | $out->setPageTitle( $this->msg( 'cargo-pagevaluesfor', $pageName )->text() ); |
37 | |
38 | $text = ''; |
39 | |
40 | $dbr = wfGetDB( DB_REPLICA ); |
41 | |
42 | $tableNames = []; |
43 | // There is an exception check later on when we query for rows, so it's safe not to |
44 | // check for existence yet |
45 | $tableNames[] = '_pageData'; |
46 | $tableNames[] = '_fileData'; |
47 | |
48 | $res = $dbr->select( |
49 | 'cargo_pages', 'table_name', |
50 | [ 'page_id' => $this->mTitle->getArticleID() ] |
51 | ); |
52 | foreach ( $res as $row ) { |
53 | $tableNames[] = $row->table_name; |
54 | } |
55 | |
56 | $toc = Linker::tocIndent(); |
57 | $tocLength = 0; |
58 | |
59 | foreach ( $tableNames as $tableName ) { |
60 | try { |
61 | $queryResults = $this->getRowsForPageInTable( $tableName ); |
62 | } catch ( Exception $e ) { |
63 | // Most likely this is because the _pageData |
64 | // table doesn't exist. |
65 | continue; |
66 | } |
67 | $numRowsOnPage = count( $queryResults ); |
68 | |
69 | // Hide _fileData if it's empty - we do this only for _fileData, |
70 | // as another table having 0 rows can indicate an error, and we'd |
71 | // like to preserve that information for debugging purposes. |
72 | if ( $numRowsOnPage === 0 && $tableName === '_fileData' ) { |
73 | continue; |
74 | } |
75 | |
76 | $tableLink = $this->getTableLink( $tableName ); |
77 | |
78 | $tableSectionHeader = $this->msg( 'cargo-pagevalues-tablevalues', $tableLink )->text(); |
79 | $tableSectionTocDisplay = $this->msg( 'cargo-pagevalues-tablevalues', $tableName )->escaped(); |
80 | $tableSectionAnchor = $this->msg( 'cargo-pagevalues-tablevalues', $tableName )->escaped(); |
81 | $tableSectionAnchor = Sanitizer::escapeIdForAttribute( $tableSectionAnchor ); |
82 | |
83 | // We construct the table of contents at the same time |
84 | // as the main text. |
85 | $toc .= Linker::tocLine( $tableSectionAnchor, $tableSectionTocDisplay, |
86 | $this->getLanguage()->formatNum( ++$tocLength ), 1 ) . Linker::tocLineEnd(); |
87 | |
88 | $h2 = Html::rawElement( 'h2', null, |
89 | Html::rawElement( 'span', [ 'class' => 'mw-headline', 'id' => $tableSectionAnchor ], $tableSectionHeader ) ); |
90 | |
91 | $text .= Html::rawElement( 'div', [ 'class' => 'cargo-pagevalues-tableinfo' ], |
92 | $h2 . $this->msg( "cargo-pagevalues-tableinfo-numrows", $numRowsOnPage ) |
93 | ); |
94 | |
95 | foreach ( $queryResults as $rowValues ) { |
96 | $tableContents = ''; |
97 | $fieldInfo = $this->getInfoForAllFields( $tableName ); |
98 | $anyFieldHasAllowedValues = false; |
99 | foreach ( $fieldInfo as $info ) { |
100 | if ( $info['allowed values'] !== '' ) { |
101 | $anyFieldHasAllowedValues = true; |
102 | } |
103 | } |
104 | foreach ( $rowValues as $field => $value ) { |
105 | // @HACK - this check should ideally |
106 | // be done earlier. |
107 | if ( strpos( $field, '__precision' ) !== false ) { |
108 | continue; |
109 | } |
110 | $tableContents .= $this->printRow( $field, $value, $fieldInfo[$field], $anyFieldHasAllowedValues ); |
111 | } |
112 | $text .= $this->printTable( $tableContents, $anyFieldHasAllowedValues ); |
113 | } |
114 | } |
115 | |
116 | // Show table of contents only if there are enough sections. |
117 | if ( count( $tableNames ) >= 3 ) { |
118 | $toc = Linker::tocList( $toc ); |
119 | $out->addHTML( $toc ); |
120 | } |
121 | |
122 | $out->addHTML( $text ); |
123 | $out->addModules( 'ext.cargo.pagevalues' ); |
124 | |
125 | return true; |
126 | } |
127 | |
128 | private function getTableLink( $tableName ) { |
129 | $originalTableName = str_replace( '__NEXT', '', $tableName ); |
130 | $isReplacementTable = substr( $tableName, -6 ) == '__NEXT'; |
131 | $viewURL = SpecialPage::getTitleFor( 'CargoTables' )->getFullURL() . "/$originalTableName"; |
132 | if ( $isReplacementTable ) { |
133 | $viewURL .= strpos( $viewURL, '?' ) ? '&' : '?'; |
134 | $viewURL .= "_replacement"; |
135 | } |
136 | |
137 | return Html::element( 'a', [ 'href' => $viewURL ], $tableName ); |
138 | } |
139 | |
140 | /** |
141 | * Used to get the information about field type and the list |
142 | * of allowed values (if any) of all fields of a table. |
143 | * |
144 | * @param string $tableName |
145 | */ |
146 | private function getInfoForAllFields( $tableName ) { |
147 | $tableSchemas = CargoUtils::getTableSchemas( [ $tableName ] ); |
148 | if ( $tableName == '_pageData' ) { |
149 | CargoUtils::addGlobalFieldsToSchema( $tableSchemas[$tableName] ); |
150 | } |
151 | $fieldDescriptions = $tableSchemas[$tableName]->mFieldDescriptions; |
152 | $fieldInfo = []; |
153 | foreach ( $fieldDescriptions as $fieldName => $fieldDescription ) { |
154 | $fieldInfo[$fieldName]['field type'] = $fieldDescription->prettyPrintType(); |
155 | if ( is_array( $fieldDescription->mAllowedValues ) ) { |
156 | $fieldInfo[$fieldName]['allowed values'] = implode( ' · ', $fieldDescription->mAllowedValues ); |
157 | } else { |
158 | $fieldInfo[$fieldName]['allowed values'] = ''; |
159 | } |
160 | } |
161 | return $fieldInfo; |
162 | } |
163 | |
164 | public function getRowsForPageInTable( $tableName ) { |
165 | $cdb = CargoUtils::getDB(); |
166 | |
167 | $sqlQuery = new CargoSQLQuery(); |
168 | $sqlQuery->mAliasedTableNames = [ $tableName => $tableName ]; |
169 | |
170 | $tableSchemas = CargoUtils::getTableSchemas( [ $tableName ] ); |
171 | |
172 | if ( $tableName == '_pageData' ) { |
173 | CargoUtils::addGlobalFieldsToSchema( $tableSchemas[$tableName] ); |
174 | } |
175 | |
176 | $sqlQuery->mTableSchemas = $tableSchemas; |
177 | |
178 | $aliasedFieldNames = []; |
179 | foreach ( $tableSchemas[$tableName]->mFieldDescriptions as $fieldName => $fieldDescription ) { |
180 | if ( $fieldDescription->mIsHidden ) { |
181 | // @TODO - do some custom formatting |
182 | } |
183 | |
184 | // $fieldAlias = str_replace( '_', ' ', $fieldName ); |
185 | $fieldAlias = $fieldName; |
186 | |
187 | if ( $fieldDescription->mIsList ) { |
188 | $aliasedFieldNames[$fieldAlias] = $fieldName . '__full'; |
189 | } elseif ( $fieldDescription->mType == 'Coordinates' ) { |
190 | $aliasedFieldNames[$fieldAlias] = $fieldName . '__full'; |
191 | } else { |
192 | $aliasedFieldNames[$fieldAlias] = $fieldName; |
193 | } |
194 | } |
195 | |
196 | $sqlQuery->mAliasedFieldNames = $aliasedFieldNames; |
197 | $sqlQuery->mOrigAliasedFieldNames = $aliasedFieldNames; |
198 | $sqlQuery->setDescriptionsAndTableNamesForFields(); |
199 | $sqlQuery->handleDateFields(); |
200 | $sqlQuery->mWhereStr = $cdb->addIdentifierQuotes( '_pageID' ) . " = " . |
201 | $this->mTitle->getArticleID(); |
202 | |
203 | $queryResults = $sqlQuery->run(); |
204 | $queryDisplayer = CargoQueryDisplayer::newFromSQLQuery( $sqlQuery ); |
205 | $formattedQueryResults = $queryDisplayer->getFormattedQueryResults( $queryResults ); |
206 | return $formattedQueryResults; |
207 | } |
208 | |
209 | /** |
210 | * Based on MediaWiki's InfoAction::addRow() |
211 | */ |
212 | public function printRow( $name, $value, $fieldInfo, $fieldHasAnyAllowedValues ) { |
213 | if ( $name == '_fullText' && strlen( $value ) > 300 ) { |
214 | $value = substr( $value, 0, 300 ) . ' ...'; |
215 | } |
216 | $text = Html::element( 'td', [ 'class' => 'cargo-pagevalues-table-field' ], $name ) . |
217 | Html::rawElement( 'td', [ 'class' => 'cargo-pagevalues-table-type' ], $fieldInfo['field type'] ); |
218 | if ( $fieldHasAnyAllowedValues ) { |
219 | $allowedValuesText = $fieldInfo['allowed values']; |
220 | // Count "middot" as only one character, not eight, when counting the string length. |
221 | $allowedValuesDisplayText = str_replace( '·', '.', $allowedValuesText ); |
222 | if ( strlen( $allowedValuesDisplayText ) > 25 ) { |
223 | $allowedValuesText = '<span class="cargoMinimizedText">' . $fieldInfo['allowed values'] . '</span>'; |
224 | } |
225 | $text .= Html::rawElement( 'td', [ 'class' => 'cargo-pagevalues-table-allowedvalues' ], $allowedValuesText ); |
226 | } |
227 | $text .= Html::rawElement( 'td', [ 'class' => 'cargo-pagevalues-table-value' ], $value ); |
228 | |
229 | return Html::rawElement( 'tr', [], $text ); |
230 | } |
231 | |
232 | /** |
233 | * Based on MediaWiki's InfoAction::addTable() |
234 | */ |
235 | public function printTable( $tableContents, $anyFieldHasAllowedValues ) { |
236 | $headerRow = '<tr><th>Field</th><th>' . $this->msg( 'cargo-field-type' )->text() . '</th>'; |
237 | if ( $anyFieldHasAllowedValues ) { |
238 | $headerRow .= '<th>' . $this->msg( 'cargo-allowed-values' )->text() . '</th>'; |
239 | } |
240 | $headerRow .= '<th>Value</th></tr>'; |
241 | return Html::rawElement( 'table', [ 'class' => 'wikitable mw-page-info' ], |
242 | $headerRow . $tableContents ) . "\n"; |
243 | } |
244 | |
245 | /** |
246 | * Don't list this in Special:SpecialPages. |
247 | */ |
248 | public function isListed() { |
249 | return false; |
250 | } |
251 | } |