Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PFFormLink
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 3
2550
0.00% covered (danger)
0.00%
0 / 1
 run
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 createFormLink
0.00% covered (danger)
0.00%
0 / 115
0.00% covered (danger)
0.00%
0 / 1
2352
 loadScriptsForPopupForm
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2use MediaWiki\MediaWikiServices;
3
4/**
5 * '#formlink' is called as:
6 *
7 * {{#formlink:form=|link text=|link type=|tooltip=|query string=|target=
8 * |popup|reload|...additional query string values...}}
9 *
10 * This function returns HTML representing a link to a form; given that
11 * no page name is entered by the user, the form must be one that
12 * creates an automatic page name, or else it will display an error
13 * message when the user clicks on the link.
14 *
15 * The first two arguments are mandatory:
16 * 'form' is the name of the PF form, and 'link text' is the text of the link.
17 * 'link type' is the type of the link: if set to 'button', the link will be
18 * a button; if set to 'post button', the link will be a button that uses the
19 * 'POST' method to send other values to the form; if set to anything else or
20 * not called, it will be a standard hyperlink.
21 * 'tooltip' sets a hovering tooltip text, if it's an actual link.
22 * 'query string' is the text to be added to the generated URL's query string
23 * (or, in the case of 'post button', to be sent as hidden inputs).
24 * 'target' is an optional value, setting the name of the page to be
25 * edited by the form.
26 * 'reload' is an optional parameter that can be used alongside either
27 * 'popup' or 'returnto'; it causes the page that the user ends up on after
28 * submitting the form to get reloaded with 'action=purge'.
29 *
30 * Example: to create a link to add data with a form called
31 * 'User' within a namespace also called 'User', and to have the form
32 * preload with the page called 'UserStub', you could call the following:
33 *
34 * {{#formlink:form=User|link text=Add a user
35 * |query string=namespace=User&preload=UserStub}}
36 */
37
38class PFFormLink {
39
40    public static function run( Parser $parser ) {
41        $params = func_get_args();
42        // We don't need the parser.
43        array_shift( $params );
44        $str = self::createFormLink( $parser, $params );
45        return [ $str, 'noparse' => true, 'isHTML' => true ];
46    }
47
48    protected static function createFormLink( Parser $parser, $params ) {
49        // Set defaults.
50        $inFormName = $inLinkStr = $inExistingPageLinkStr = $inLinkType =
51            $inTooltip = $inTargetName = '';
52        $hasPopup = $hasReturnTo = false;
53        $className = static::class;
54        if ( $className == 'PFQueryFormLink' ) {
55            $inLinkStr = wfMessage( 'runquery' )->parse();
56        }
57        $inCreatePage = false;
58        $classStr = '';
59        $inQueryArr = [];
60        $targetWindow = '_self';
61
62        // Needed for the 'next' icon.
63        $parser->getOutput()->addModules( [ 'oojs-ui.styles.icons-movement' ] );
64
65        // assign params
66        // - support unlabelled params, for backwards compatibility
67        // - parse and sanitize all parameter values
68        foreach ( $params as $i => $param ) {
69            $elements = explode( '=', $param, 2 );
70
71            // set param_name and value
72            if ( count( $elements ) > 1 ) {
73                $param_name = trim( $elements[0] );
74
75                // parse (and sanitize) parameter values
76                $value = trim( $parser->recursiveTagParse( $elements[1] ) );
77            } else {
78                $param_name = null;
79
80                // parse (and sanitize) parameter values
81                $value = trim( $parser->recursiveTagParse( $param ) );
82            }
83
84            if ( $param_name == 'form' ) {
85                $inFormName = $value;
86            } elseif ( $param_name == 'link text' ) {
87                $inLinkStr = $value;
88            } elseif ( $param_name == 'existing page link text' ) {
89                $inExistingPageLinkStr = $value;
90            } elseif ( $param_name == 'link type' ) {
91                $inLinkType = $value;
92            } elseif ( $param_name == 'query string' ) {
93                $inQueryArr = PFAutoEdit::convertQueryString( $value, $inQueryArr );
94            } elseif ( $param_name == 'tooltip' ) {
95                $inTooltip = Sanitizer::decodeCharReferences( $value );
96            } elseif ( $param_name == 'target' ) {
97                $inTargetName = Sanitizer::decodeCharReferences( $value );
98            } elseif ( $param_name == null && $value == 'popup' ) {
99                self::loadScriptsForPopupForm( $parser );
100                $classStr = 'popupformlink';
101                $hasPopup = true;
102            } elseif ( $param_name == null && $value == 'reload' ) {
103                $classStr .= ' reload';
104                $inQueryArr['reload'] = '1';
105            } elseif ( $param_name == null && $value == 'new window' ) {
106                $targetWindow = '_blank';
107            } elseif ( $param_name == null && $value == 'create page' ) {
108                $inCreatePage = true;
109            } elseif ( $param_name !== null ) {
110                $value = urlencode( $value );
111                parse_str( "$param_name=$value", $arr );
112                $inQueryArr = PFUtils::arrayMergeRecursiveDistinct( $inQueryArr, $arr );
113                if ( $param_name == 'returnto' ) {
114                    $hasReturnTo = true;
115                }
116            }
117        }
118
119        if ( $hasPopup && $hasReturnTo ) {
120            return '<div class="error">Error: \'popup\' and \'returnto\' cannot be set in the same function.</div>';
121        }
122
123        // Not the most graceful way to do this, but it is the
124        // easiest - if this is the #formredlink function, just
125        // ignore whatever values were passed in for these params.
126        if ( $className == 'PFFormRedLink' ) {
127            $inLinkType = $inTooltip = null;
128        }
129
130        // If "red link only" was specified, and a target page was
131        // specified, and it exists, just link to the page.
132        if ( $inTargetName != '' ) {
133            // Call urldecode() on it, in case the target was
134            // set via {{PAGENAMEE}}, and the page name contains
135            // an apostrophe or other unusual character.
136            $targetTitle = Title::newFromText( urldecode( $inTargetName ) );
137            $targetPageExists = ( $targetTitle != '' && $targetTitle->exists() );
138        } else {
139            $targetPageExists = false;
140        }
141
142        if ( $className == 'PFFormRedLink' && $targetPageExists ) {
143            $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
144            if ( $inExistingPageLinkStr == '' ) {
145                return $linkRenderer->makeKnownLink( $targetTitle );
146            } else {
147                return $linkRenderer->makeKnownLink( $targetTitle, $inExistingPageLinkStr );
148            }
149        }
150
151        // The page doesn't exist, so if 'create page' was
152        // specified, create the page now.
153        if ( $className == 'PFFormRedLink' &&
154            $inCreatePage && $inTargetName != '' ) {
155            $targetTitle = Title::newFromText( $inTargetName );
156            PFFormLinker::createPageWithForm( $targetTitle, $inFormName, $inQueryArr );
157        }
158
159        if ( $className == 'PFQueryFormLink' ) {
160            $formSpecialPage = PFUtils::getSpecialPage( 'RunQuery' );
161        } else {
162            $formSpecialPage = PFUtils::getSpecialPage( 'FormEdit' );
163        }
164        $formSpecialPageTitle = $formSpecialPage->getPageTitle();
165
166        if ( $inFormName == '' ) {
167            $query = [ 'target' => $inTargetName ];
168            $link_url = $formSpecialPageTitle->getLocalURL( $query );
169        } elseif ( strpos( $inFormName, '/' ) == true ) {
170            $query = [ 'form' => $inFormName, 'target' => $inTargetName ];
171            $link_url = $formSpecialPageTitle->getLocalURL( $query );
172        } else {
173            $link_url = $formSpecialPageTitle->getLocalURL() . "/$inFormName";
174            if ( !empty( $inTargetName ) ) {
175                $link_url .= "/$inTargetName";
176            }
177            $link_url = str_replace( ' ', '_', $link_url );
178        }
179        $hidden_inputs = "";
180        if ( !empty( $inQueryArr ) ) {
181            // Special handling for the buttons - query string
182            // has to be turned into hidden inputs.
183            if ( $inLinkType == 'button' || $inLinkType == 'post button' ) {
184                $query_components = explode( '&', http_build_query( $inQueryArr, '', '&' ) );
185
186                foreach ( $query_components as $query_component ) {
187                    $var_and_val = explode( '=', $query_component, 2 );
188                    if ( count( $var_and_val ) == 2 ) {
189                        $hidden_inputs .= Html::hidden( urldecode( $var_and_val[0] ), urldecode( $var_and_val[1] ) );
190                    }
191                }
192            } else {
193                $link_url .= ( strstr( $link_url, '?' ) ) ? '&' : '?';
194                $link_url .= str_replace( '+', '%20', http_build_query( $inQueryArr, '', '&' ) );
195            }
196        }
197        if ( $inLinkType == 'button' || $inLinkType == 'post button' ) {
198            $parser->getOutput()->setEnableOOUI( true );
199            OutputPage::setupOOUI();
200            $buttonAttrs = [
201                'type' => 'submit',
202                'label' => $inLinkStr,
203                'title' => $inTooltip,
204                'flags' => 'progressive',
205                'icon' => 'next'
206            ];
207            $buttonHTML = new OOUI\ButtonInputWidget( $buttonAttrs );
208            $formAttrs = [
209                'action' => $link_url,
210                'method' => ( $inLinkType == 'button' ) ? 'get' : 'post',
211                'class' => $classStr,
212                'target' => $targetWindow
213            ];
214            $str = Html::rawElement( 'form', $formAttrs, $buttonHTML . $hidden_inputs );
215        } else {
216            // If a target page has been specified but it doesn't
217            // exist, make it a red link.
218            if ( !empty( $inTargetName ) ) {
219                if ( !$targetPageExists ) {
220                    $classStr .= " new";
221                }
222                // If no link string was specified, make it
223                // the name of the page.
224                if ( $inLinkStr == '' ) {
225                    $inLinkStr = $inTargetName;
226                }
227            }
228            $str = Html::rawElement( 'a', [ 'href' => $link_url, 'class' => $classStr, 'title' => $inTooltip, 'target' => $targetWindow ], $inLinkStr );
229        }
230
231        return $str;
232    }
233
234    public static function loadScriptsForPopupForm( Parser $parser ) {
235        $parser->getOutput()->addModules( [ 'ext.pageforms.popupformedit' ] );
236        return true;
237    }
238}