MediaWiki master
FormSpecialPage.php
Go to the documentation of this file.
1<?php
10namespace MediaWiki\SpecialPage;
11
18use StatusValue;
19
27abstract class FormSpecialPage extends SpecialPage {
32 protected $par = null;
33
38 protected $reauthPostData = null;
39
44 abstract protected function getFormFields();
45
51 protected function preHtml() {
52 return '';
53 }
54
60 protected function postHtml() {
61 return '';
62 }
63
67 protected function alterForm( HTMLForm $form ) {
68 }
69
76 protected function getMessagePrefix() {
77 return strtolower( $this->getName() );
78 }
79
86 protected function getDisplayFormat() {
87 return 'table';
88 }
89
94 protected function getForm() {
95 $context = $this->getContext();
96 $onSubmit = $this->onSubmit( ... );
97
98 if ( $this->reauthPostData ) {
99 // Restore POST data
100 $context = new DerivativeContext( $context );
101 $oldRequest = $this->getRequest();
102 $context->setRequest( new DerivativeRequest(
103 $oldRequest, $this->reauthPostData + $oldRequest->getQueryValues(), true
104 ) );
105
106 // But don't treat it as a "real" submission just in case of some
107 // crazy kind of CSRF.
108 $onSubmit = static fn () => false;
109 }
110
111 $form = HTMLForm::factory(
112 $this->getDisplayFormat(),
113 $this->getFormFields(),
114 $context,
115 $this->getMessagePrefix()
116 );
117 if ( !$this->requiresPost() ) {
118 $form->setMethod( 'get' );
119 }
120 $form->setSubmitCallback( $onSubmit );
121 if ( $this->getDisplayFormat() !== 'ooui' ) {
122 // No legend and wrapper by default in OOUI forms, but can be set manually
123 // from alterForm()
124 $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
125 }
126
127 $headerMsg = $this->msg( $this->getMessagePrefix() . '-text' );
128 if ( !$headerMsg->isDisabled() ) {
129 $form->addHeaderHtml( $headerMsg->parseAsBlock() );
130 }
131
132 $form->addPreHtml( $this->preHtml() );
133 $form->addPostHtml( $this->postHtml() );
134
135 // Give precedence to subpage syntax
136 $field = $this->getSubpageField();
137 // cast to string so that "0" is not thrown away
138 if ( strval( $this->par ) !== '' && $field ) {
139 $this->getRequest()->setVal( $form->getField( $field )->getName(), $this->par );
140 $form->setTitle( $this->getPageTitle() );
141 }
142 $this->alterForm( $form );
143 if ( $form->getMethod() == 'post' ) {
144 // Retain query parameters (uselang etc) on POST requests
145 $params = array_diff_key(
146 $this->getRequest()->getQueryValues(), [ 'title' => null ] );
147 $form->addHiddenField( 'redirectparams', wfArrayToCgi( $params ) );
148 }
149
150 // Give hooks a chance to alter the form, adding extra fields or text etc
151 $this->getHookRunner()->onSpecialPageBeforeFormDisplay( $this->getName(), $form );
152
153 return $form;
154 }
155
165 abstract public function onSubmit( array $data /* HTMLForm $form = null */ );
166
172 public function onSuccess() {
173 }
174
180 public function execute( $par ) {
181 $this->setParameter( $par );
182 $this->setHeaders();
183 $this->outputHeader();
184
185 // This will throw exceptions if there's a problem
186 $this->checkExecutePermissions( $this->getUser() );
187
188 $securityLevel = $this->getLoginSecurityLevel();
189 if ( $securityLevel !== false && !$this->checkLoginSecurityLevel( $securityLevel ) ) {
190 return;
191 }
192
193 $form = $this->getForm();
194 // GET forms can be set as includable
195 if ( !$this->including() ) {
196 $result = $this->getShowAlways() ? $form->showAlways() : $form->show();
197 } else {
198 $result = $form->prepareForm()->tryAuthorizedSubmit();
199 }
200 if ( $result === true || ( $result instanceof StatusValue && $result->isGood() ) ) {
201 $this->onSuccess();
202 }
203 }
204
210 protected function getShowAlways() {
211 return false;
212 }
213
218 protected function setParameter( $par ) {
219 $this->par = $par;
220 }
221
227 protected function getSubpageField() {
228 return false;
229 }
230
237 protected function checkExecutePermissions( User $user ) {
238 $this->checkPermissions();
239
240 if ( $this->requiresUnblock() ) {
241 $block = $user->getBlock();
242 if ( $block && $block->isSitewide() ) {
243 throw new UserBlockedError(
244 $block,
245 $user,
246 $this->getLanguage(),
247 $this->getRequest()->getIP()
248 );
249 }
250 }
251
252 if ( $this->requiresWrite() ) {
253 $this->checkReadOnly();
254 }
255 }
256
262 public function requiresPost() {
263 return true;
264 }
265
270 public function requiresWrite() {
271 return $this->requiresPost();
272 }
273
278 public function requiresUnblock() {
279 return $this->requiresPost();
280 }
281
288 protected function setReauthPostData( array $data ) {
289 $this->reauthPostData = $data;
290 }
291}
292
294class_alias( FormSpecialPage::class, 'FormSpecialPage' );
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
An IContextSource implementation which will inherit context from another source but allow individual ...
Show an error when the user tries to do something whilst blocked.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:208
Similar to MediaWiki\Request\FauxRequest, but only fakes URL parameters and method (POST or GET) and ...
Special page which uses an HTMLForm to handle processing.
getMessagePrefix()
Get message prefix for HTMLForm.
requiresUnblock()
Whether this action cannot be executed by a blocked user, default to requiresPost()
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
requiresPost()
Whether this action should using POST method to submit, default to true.
getShowAlways()
Whether the form should always be shown despite the success of submission.
getForm()
Get the HTMLForm to control behavior.
setParameter( $par)
Maybe do something interesting with the subpage parameter.
execute( $par)
Basic SpecialPage workflow: get a form, send it to the user; get some data back,.
requiresWrite()
Whether this action requires the wiki not to be locked, default to requiresPost()
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
setReauthPostData(array $data)
Preserve POST data across reauthentication.
string null $par
The subpage of the special page.
array null $reauthPostData
POST data preserved across re-authentication.
getSubpageField()
Override this function to set the field name used in the subpage syntax.
checkExecutePermissions(User $user)
Called from execute() to check if the given user can perform this action.
getFormFields()
Get an HTMLForm descriptor array.
preHtml()
Add pre-HTML to the form.
onSubmit(array $data)
Process the form on submission.
getDisplayFormat()
Get display format for the form.
postHtml()
Add post-HTML to the form.
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getLoginSecurityLevel()
Tells if the special page does something security-sensitive and needs extra defense against a stolen ...
including( $x=null)
Whether the special page is being evaluated via transclusion.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
getName()
Get the canonical, unlocalized name of this special page without namespace.
checkLoginSecurityLevel( $level=null)
Verifies that the user meets the security level, possibly reauthenticating them in the process.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
User class for the MediaWiki software.
Definition User.php:130
getBlock( $freshness=IDBAccessObject::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition User.php:1426
Generic operation result class Has warning/error list, boolean status and arbitrary value.
isGood()
Returns whether the operation completed and didn't have any error or warnings.