Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 164
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialCargoQuery
0.00% covered (danger)
0.00%
0 / 164
0.00% covered (danger)
0.00%
0 / 9
1122
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 displayInputRow
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 displayTextArea
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 displayOrderByInput
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
42
 displayInputForm
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 getWikitextForQuery
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
132
 displayBottomPane
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Shows the results of a Cargo query.
4 *
5 * @author Yaron Koren
6 * @ingroup Cargo
7 */
8
9class SpecialCargoQuery extends SpecialPage {
10
11    /**
12     * Constructor
13     */
14    public function __construct() {
15        parent::__construct( 'CargoQuery', 'runcargoqueries' );
16    }
17
18    public function execute( $query ) {
19        $this->checkPermissions();
20
21        $this->setHeaders();
22        $out = $this->getOutput();
23        $req = $this->getRequest();
24        $out->enableOOUI();
25
26        $out->addModules( 'ext.cargo.main' );
27        $out->addModules( 'ext.cargo.cargoquery' );
28
29        if ( $req->getCheck( 'tables' ) ) {
30            // Allow operators to control how many Cargo queries any one user can run.
31            if ( $this->getUser()->pingLimiter( 'cargo-query' ) ) {
32                throw new ThrottledError();
33            }
34
35            try {
36                $rep = new CargoQueryPage();
37            } catch ( MWException $e ) {
38                $out->addHTML( CargoUtils::formatError( $e->getMessage() ) );
39                return;
40            }
41            $rep->execute( $query );
42        }
43
44        $formHTML = $this->displayInputForm();
45
46        if ( $req->getCheck( 'tables' ) ) {
47            $html = $this->displayBottomPane( $this->msg( 'cargo-viewdata-modifyquery' ), $formHTML );
48            $wikitext = $this->getWikitextForQuery();
49            $html .= $this->displayBottomPane( $this->msg( 'cargo-viewdata-viewwikitext' ), $wikitext );
50        } else {
51            $html = $formHTML;
52        }
53
54        $out->addHTML( $html );
55    }
56
57    protected function getGroupName() {
58        return 'cargo';
59    }
60
61    /**
62     * This method is used for generating the input fields
63     * @param string $labelText
64     * @param string $fieldName
65     * @param int $size
66     * @return string
67     */
68    public function displayInputRow( $labelText, $fieldName, $size ) {
69        $req = $this->getRequest();
70
71        $label = Html::element( 'label', [ 'for' => $fieldName ], $labelText );
72        $row = "\n\t" . Html::rawElement( 'td', [ 'class' => 'mw-label' ], $label );
73        $input = new OOUI\TextInputWidget( [
74            'classes' => [ 'ext-cargo-' . $fieldName ],
75            'value' => $req->getVal( $fieldName )
76        ] );
77        $row .= "\n\t" . Html::rawElement( 'td', null, $input );
78        return Html::rawElement( 'tr', [ 'class' => 'ext-cargo-tr-' . $fieldName ], $row ) . "\n";
79    }
80
81    public function displayTextArea( $labelText, $fieldName, $size ) {
82        $req = $this->getRequest();
83
84        $label = Html::element( 'label', [ 'for' => $fieldName ], $labelText );
85        $row = "\n\t" . Html::rawElement( 'td', [ 'class' => 'mw-label' ], $label );
86        $input = new OOUI\MultilineTextInputWidget( [
87            'classes' => [ 'ext-cargo-' . $fieldName ],
88            'value' => $req->getVal( $fieldName )
89        ] );
90        $row .= "\n\t" . Html::rawElement( 'td', null, $input ) . "\n";
91        return Html::rawElement( 'tr', [ 'class' => 'ext-cargo-tr-' . $fieldName ], $row ) . "\n";
92    }
93
94    public function displayOrderByInput( $rowNum, $orderByValue, $orderByDirection ) {
95        $text = "\n" . '<tr class="orderByRow" data-order-by-num=' . $rowNum . '>';
96        if ( $rowNum == 0 ) {
97            $text .= '<td class="mw-label">' .
98                '<label for="order_by">' . $this->msg( 'cargo-viewdata-orderby' )->parse() . '</td>';
99        } else {
100            $text .= '<td></td>';
101        }
102        $options = [];
103        $value = '';
104        array_push( $options, [ 'data' => 'ASC', 'label' => 'ASC' ] );
105        if ( $orderByDirection == 'ASC' ) {
106            $value = 'ASC';
107        }
108        array_push( $options, [ 'data' => 'DESC', 'label' => 'DESC' ] );
109        if ( $orderByDirection == 'DESC' ) {
110            $value = 'DESC';
111        }
112        $directionSelect = new OOUI\DropdownInputWidget( [
113            'options' => $options,
114            'id' => 'order_by_options[' . $rowNum . ']',
115            'value' => $value,
116            'name' => 'order_by_options[' . $rowNum . ']'
117        ] );
118        $orderByInput = new OOUI\TextInputWidget( [
119            'id' => 'order_by[' . $rowNum . ']',
120            'value' => $orderByValue
121        ] );
122        $button = new OOUI\ButtonWidget( [
123            'id' => ( $rowNum == 0 ) ? 'addButton' : 'deleteButton',
124            'icon' => ( $rowNum == 0 ) ? 'add' : 'subtract'
125        ] );
126        $orderByRow = new OOUI\HorizontalLayout( [
127            'items' => [
128                $orderByInput,
129                $directionSelect,
130                $button,
131            ]
132        ] );
133        $text .= '<td>' . $orderByRow;
134
135        return $text;
136    }
137
138    public function displayInputForm() {
139        $req = $this->getRequest();
140        // Add the name of this special page as a hidden input, in
141        // case the wiki doesn't use nice URLs.
142        $hiddenTitleInput = Html::hidden( 'title', $this->getPageTitle()->getFullText() );
143
144        $text = <<<END
145<form id="queryform">
146$hiddenTitleInput
147<table class="cargoQueryTable" id="cargoQueryTable" >
148<tbody>
149END;
150
151        $text .= $this->displayInputRow( $this->msg( 'cargo-viewdata-tables' )->parse(), 'tables', 100 );
152        $text .= $this->displayInputRow( $this->msg( 'cargo-viewdata-fields' )->parse(), 'fields', 100 );
153        $text .= $this->displayTextArea( $this->msg( 'cargo-viewdata-where' )->parse(), 'where', 100 );
154        $text .= $this->displayTextArea( $this->msg( 'cargo-viewdata-joinon' )->parse(), 'join_on', 100 );
155        $text .= $this->displayInputRow( $this->msg( 'cargo-viewdata-groupby' )->parse(), 'group_by', 100 );
156        $text .= $this->displayTextArea( $this->msg( 'cargo-viewdata-having' )->parse(), 'having', 100 );
157        $orderByValues = $req->getArray( 'order_by' );
158        if ( $orderByValues != null ) {
159            $orderByDirections = $req->getArray( 'order_by_options' );
160            $rowNum = 0;
161            foreach ( $orderByValues as $i => $curOrderBy ) {
162                $orderByDir = ( $orderByDirections == null ) ? null : $orderByDirections[$i];
163                $text .= $this->displayOrderByInput( $rowNum++, $curOrderBy, $orderByDir );
164            }
165        } else {
166            $text .= $this->displayOrderByInput( 0, null, null );
167        }
168        $text .= $this->displayInputRow( $this->msg( 'cargo-viewdata-limit' )->parse(), 'limit', 3 );
169        $text .= $this->displayInputRow( $this->msg( 'cargo-viewdata-offset' )->parse(), 'offset', 3 );
170        $formatLabel = '<label for="format">' . $this->msg( 'cargo-viewdata-format' )->parse();
171        $options = [];
172        $formatOptionDefault = $this->msg( 'cargo-viewdata-defaultformat' )->parse();
173        array_push( $options, [ 'data' => '', 'label' => '(' . $formatOptionDefault . ')' ] );
174        $value = '';
175        $formatClasses = CargoQueryDisplayer::getAllFormatClasses();
176        foreach ( $formatClasses as $formatName => $formatClass ) {
177            if ( $formatName == $req->getVal( 'format' ) ) {
178                $value = $formatName;
179            }
180            array_push( $options, [ 'data' => $formatName, 'label' => $formatName ] );
181        }
182        $formatDropdown = new OOUI\DropdownInputWIdget( [
183            'options' => $options,
184            'name' => 'format',
185            'id' => 'format',
186            'value' => $value
187        ] );
188        $text .= <<<END
189<tr class="ext-cargo-tr-format">
190<td class="mw-label">
191$formatLabel
192</td>
193<td>$formatDropdown
194
195END;
196        $submitButton = new OOUI\ButtonInputWidget( [
197            'label' => $this->msg( 'htmlform-submit' )->parse(),
198            'type' => 'submit',
199            'flags' => [ 'primary', 'progressive' ]
200        ] );
201        $text .= <<<END
202
203</select>
204</td>
205</tr>
206</tbody>
207</table>
208<br>
209$submitButton
210</form>
211
212END;
213        return $text;
214    }
215
216    public function getWikitextForQuery() {
217        $req = $this->getRequest();
218
219        $wikitext = "{{#cargo_query:\n";
220        $vals = $req->getValues();
221        $firstParam = true;
222        foreach ( $vals as $key => $val ) {
223            if ( $key == 'title' || $key == 'order_by_options' ) {
224                continue;
225            }
226            $key = str_replace( '_', ' ', $key );
227            if ( $key == 'order by' && is_array( $val ) ) {
228                // Possibly no longer necessary.
229                $orderByVal = '';
230                foreach ( $val as $i => $orderByField ) {
231                    if ( $orderByField == '' ) {
232                        continue;
233                    }
234                    if ( array_key_exists( 'order_by_options', $vals ) ) {
235                        $option = $vals['order_by_options'][$i];
236                    } else {
237                        $option = '';
238                    }
239                    $orderByVal .= $orderByField . ' ' . $option . ', ';
240                }
241                $val = $orderByVal;
242            }
243            $val = trim( $val );
244            $val = trim( $val, ',' );
245            if ( $val == '' ) {
246                continue;
247            }
248            if ( $firstParam ) {
249                $firstParam = false;
250            } else {
251                $wikitext .= '|';
252            }
253            $wikitext .= "$key=$val\n";
254        }
255        $wikitext .= "}}";
256
257        return '<pre>' . htmlspecialchars( $wikitext ) . '</pre>';
258    }
259
260    private function displayBottomPane( $paneName, $paneText ) {
261        $html = <<<END
262<div style="max-width: 70em;">
263<span style="width: 100%;" class="oo-ui-widget oo-ui-widget-enabled oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-indicatorElement oo-ui-labelElement oo-ui-buttonWidget">
264<a href="#" class="specialCargoQuery-extraPane-toggle oo-ui-buttonElement-button" role="button" tabindex="0" aria-disabled="false" rel="nofollow">
265$paneName
266<span class="oo-ui-indicatorElement-indicator oo-ui-indicator-down"></span>
267</a>
268</span>
269<div class="specialCargoQuery-extraPane">
270$paneText
271</div>
272</div>
273
274END;
275        return $html;
276    }
277
278}