MediaWiki master
FormSpecialPage.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\SpecialPage;
25
32
40abstract class FormSpecialPage extends SpecialPage {
45 protected $par = null;
46
51 protected $reauthPostData = null;
52
57 abstract protected function getFormFields();
58
64 protected function preHtml() {
65 return '';
66 }
67
73 protected function postHtml() {
74 return '';
75 }
76
82 protected function preText() {
83 return $this->preHtml();
84 }
85
91 protected function postText() {
92 return $this->postHtml();
93 }
94
99 protected function alterForm( HTMLForm $form ) {
100 }
101
108 protected function getMessagePrefix() {
109 return strtolower( $this->getName() );
110 }
111
118 protected function getDisplayFormat() {
119 return 'table';
120 }
121
126 protected function getForm() {
127 $context = $this->getContext();
128 $onSubmit = [ $this, 'onSubmit' ];
129
130 if ( $this->reauthPostData ) {
131 // Restore POST data
132 $context = new DerivativeContext( $context );
133 $oldRequest = $this->getRequest();
134 $context->setRequest( new DerivativeRequest(
135 $oldRequest, $this->reauthPostData + $oldRequest->getQueryValues(), true
136 ) );
137
138 // But don't treat it as a "real" submission just in case of some
139 // crazy kind of CSRF.
140 $onSubmit = static function () {
141 return false;
142 };
143 }
144
145 $form = HTMLForm::factory(
146 $this->getDisplayFormat(),
147 $this->getFormFields(),
148 $context,
149 $this->getMessagePrefix()
150 );
151 if ( !$this->requiresPost() ) {
152 $form->setMethod( 'get' );
153 }
154 $form->setSubmitCallback( $onSubmit );
155 if ( $this->getDisplayFormat() !== 'ooui' ) {
156 // No legend and wrapper by default in OOUI forms, but can be set manually
157 // from alterForm()
158 $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
159 }
160
161 $headerMsg = $this->msg( $this->getMessagePrefix() . '-text' );
162 if ( !$headerMsg->isDisabled() ) {
163 $form->addHeaderText( $headerMsg->parseAsBlock() );
164 }
165
166 // preText / postText are deprecated, but we need to keep calling them until the end of
167 // the deprecation process so a subclass overriding *Text and *Html both work
168 $form->addPreText( $this->preText() );
169 $form->addPostText( $this->postText() );
170
171 // Give precedence to subpage syntax
172 $field = $this->getSubpageField();
173 if ( $this->par && $field ) {
174 $this->getRequest()->setVal( $form->getField( $field )->getName(), $this->par );
175 $form->setTitle( $this->getPageTitle() );
176 }
177 $this->alterForm( $form );
178 if ( $form->getMethod() == 'post' ) {
179 // Retain query parameters (uselang etc) on POST requests
180 $params = array_diff_key(
181 $this->getRequest()->getQueryValues(), [ 'title' => null ] );
182 $form->addHiddenField( 'redirectparams', wfArrayToCgi( $params ) );
183 }
184
185 // Give hooks a chance to alter the form, adding extra fields or text etc
186 $this->getHookRunner()->onSpecialPageBeforeFormDisplay( $this->getName(), $form );
187
188 return $form;
189 }
190
200 abstract public function onSubmit( array $data /* HTMLForm $form = null */ );
201
207 public function onSuccess() {
208 }
209
215 public function execute( $par ) {
216 $this->setParameter( $par );
217 $this->setHeaders();
218 $this->outputHeader();
219
220 // This will throw exceptions if there's a problem
221 $this->checkExecutePermissions( $this->getUser() );
222
223 $securityLevel = $this->getLoginSecurityLevel();
224 if ( $securityLevel !== false && !$this->checkLoginSecurityLevel( $securityLevel ) ) {
225 return;
226 }
227
228 $form = $this->getForm();
229 // GET forms can be set as includable
230 if ( !$this->including() ) {
231 $result = $this->getShowAlways() ? $form->showAlways() : $form->show();
232 } else {
233 $result = $form->prepareForm()->tryAuthorizedSubmit();
234 }
235 if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
236 $this->onSuccess();
237 }
238 }
239
245 protected function getShowAlways() {
246 return false;
247 }
248
253 protected function setParameter( $par ) {
254 $this->par = $par;
255 }
256
262 protected function getSubpageField() {
263 return false;
264 }
265
272 protected function checkExecutePermissions( User $user ) {
273 $this->checkPermissions();
274
275 if ( $this->requiresUnblock() ) {
276 $block = $user->getBlock();
277 if ( $block && $block->isSitewide() ) {
278 throw new UserBlockedError(
279 $block,
280 $user,
281 $this->getLanguage(),
282 $this->getRequest()->getIP()
283 );
284 }
285 }
286
287 if ( $this->requiresWrite() ) {
288 $this->checkReadOnly();
289 }
290 }
291
297 public function requiresPost() {
298 return true;
299 }
300
305 public function requiresWrite() {
306 return $this->requiresPost();
307 }
308
313 public function requiresUnblock() {
314 return $this->requiresPost();
315 }
316
323 protected function setReauthPostData( array $data ) {
324 $this->reauthPostData = $data;
325 }
326}
327
332class_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....
array $params
The job parameters.
An IContextSource implementation which will inherit context from another source but allow individual ...
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
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.
postText()
Add post-text to the form.
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 sub-page 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.
preText()
Add pre-text to the form.
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 Per default the message key is the canonical name o...
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:54
internal since 1.36
Definition User.php:93
getBlock( $freshness=IDBAccessObject::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition User.php:1431
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Show an error when the user tries to do something whilst blocked.