Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Preferences often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Preferences, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 50 | class Preferences { |
||
| 51 | /** @var array */ |
||
| 52 | protected static $defaultPreferences = null; |
||
| 53 | |||
| 54 | /** @var array */ |
||
| 55 | protected static $saveFilters = [ |
||
| 56 | 'timecorrection' => [ 'Preferences', 'filterTimezoneInput' ], |
||
| 57 | 'cols' => [ 'Preferences', 'filterIntval' ], |
||
| 58 | 'rows' => [ 'Preferences', 'filterIntval' ], |
||
| 59 | 'rclimit' => [ 'Preferences', 'filterIntval' ], |
||
| 60 | 'wllimit' => [ 'Preferences', 'filterIntval' ], |
||
| 61 | 'searchlimit' => [ 'Preferences', 'filterIntval' ], |
||
| 62 | ]; |
||
| 63 | |||
| 64 | // Stuff that shouldn't be saved as a preference. |
||
| 65 | private static $saveBlacklist = [ |
||
| 66 | 'realname', |
||
| 67 | 'emailaddress', |
||
| 68 | ]; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * @return array |
||
| 72 | */ |
||
| 73 | static function getSaveBlacklist() { |
||
| 76 | |||
| 77 | /** |
||
| 78 | * @throws MWException |
||
| 79 | * @param User $user |
||
| 80 | * @param IContextSource $context |
||
| 81 | * @return array|null |
||
| 82 | */ |
||
| 83 | static function getPreferences( $user, IContextSource $context ) { |
||
| 107 | |||
| 108 | /** |
||
| 109 | * Loads existing values for a given array of preferences |
||
| 110 | * @throws MWException |
||
| 111 | * @param User $user |
||
| 112 | * @param IContextSource $context |
||
| 113 | * @param array $defaultPreferences Array to load values for |
||
| 114 | * @return array|null |
||
| 115 | */ |
||
| 116 | static function loadPreferenceValues( $user, $context, &$defaultPreferences ) { |
||
| 157 | |||
| 158 | /** |
||
| 159 | * Pull option from a user account. Handles stuff like array-type preferences. |
||
| 160 | * |
||
| 161 | * @param string $name |
||
| 162 | * @param array $info |
||
| 163 | * @param User $user |
||
| 164 | * @return array|string |
||
| 165 | */ |
||
| 166 | static function getOptionFromUser( $name, $info, $user ) { |
||
| 202 | |||
| 203 | /** |
||
| 204 | * @param User $user |
||
| 205 | * @param IContextSource $context |
||
| 206 | * @param array $defaultPreferences |
||
| 207 | * @return void |
||
| 208 | */ |
||
| 209 | static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 210 | global $wgAuth, $wgContLang, $wgParser, $wgDisableAuthManager; |
||
| 211 | |||
| 212 | $config = $context->getConfig(); |
||
| 213 | // retrieving user name for GENDER and misc. |
||
| 214 | $userName = $user->getName(); |
||
| 215 | |||
| 216 | # # User info ##################################### |
||
| 217 | // Information panel |
||
| 218 | $defaultPreferences['username'] = [ |
||
| 219 | 'type' => 'info', |
||
| 220 | 'label-message' => [ 'username', $userName ], |
||
| 221 | 'default' => $userName, |
||
| 222 | 'section' => 'personal/info', |
||
| 223 | ]; |
||
| 224 | |||
| 225 | # Get groups to which the user belongs |
||
| 226 | $userEffectiveGroups = $user->getEffectiveGroups(); |
||
| 227 | $userGroups = $userMembers = []; |
||
| 228 | foreach ( $userEffectiveGroups as $ueg ) { |
||
| 229 | if ( $ueg == '*' ) { |
||
| 230 | // Skip the default * group, seems useless here |
||
| 231 | continue; |
||
| 232 | } |
||
| 233 | $groupName = User::getGroupName( $ueg ); |
||
| 234 | $userGroups[] = User::makeGroupLinkHTML( $ueg, $groupName ); |
||
| 235 | |||
| 236 | $memberName = User::getGroupMember( $ueg, $userName ); |
||
| 237 | $userMembers[] = User::makeGroupLinkHTML( $ueg, $memberName ); |
||
| 238 | } |
||
| 239 | asort( $userGroups ); |
||
| 240 | asort( $userMembers ); |
||
| 241 | |||
| 242 | $lang = $context->getLanguage(); |
||
| 243 | |||
| 244 | $defaultPreferences['usergroups'] = [ |
||
| 245 | 'type' => 'info', |
||
| 246 | 'label' => $context->msg( 'prefs-memberingroups' )->numParams( |
||
| 247 | count( $userGroups ) )->params( $userName )->parse(), |
||
| 248 | 'default' => $context->msg( 'prefs-memberingroups-type' ) |
||
| 249 | ->rawParams( $lang->commaList( $userGroups ), $lang->commaList( $userMembers ) ) |
||
| 250 | ->escaped(), |
||
| 251 | 'raw' => true, |
||
| 252 | 'section' => 'personal/info', |
||
| 253 | ]; |
||
| 254 | |||
| 255 | $editCount = Linker::link( SpecialPage::getTitleFor( "Contributions", $userName ), |
||
| 256 | $lang->formatNum( $user->getEditCount() ) ); |
||
| 257 | |||
| 258 | $defaultPreferences['editcount'] = [ |
||
| 259 | 'type' => 'info', |
||
| 260 | 'raw' => true, |
||
| 261 | 'label-message' => 'prefs-edits', |
||
| 262 | 'default' => $editCount, |
||
| 263 | 'section' => 'personal/info', |
||
| 264 | ]; |
||
| 265 | |||
| 266 | if ( $user->getRegistration() ) { |
||
|
|
|||
| 267 | $displayUser = $context->getUser(); |
||
| 268 | $userRegistration = $user->getRegistration(); |
||
| 269 | $defaultPreferences['registrationdate'] = [ |
||
| 270 | 'type' => 'info', |
||
| 271 | 'label-message' => 'prefs-registration', |
||
| 272 | 'default' => $context->msg( |
||
| 273 | 'prefs-registration-date-time', |
||
| 274 | $lang->userTimeAndDate( $userRegistration, $displayUser ), |
||
| 275 | $lang->userDate( $userRegistration, $displayUser ), |
||
| 276 | $lang->userTime( $userRegistration, $displayUser ) |
||
| 277 | )->parse(), |
||
| 278 | 'section' => 'personal/info', |
||
| 279 | ]; |
||
| 280 | } |
||
| 281 | |||
| 282 | $canViewPrivateInfo = $user->isAllowed( 'viewmyprivateinfo' ); |
||
| 283 | $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' ); |
||
| 284 | |||
| 285 | // Actually changeable stuff |
||
| 286 | $realnameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'realname' ) |
||
| 287 | : AuthManager::singleton()->allowsPropertyChange( 'realname' ); |
||
| 288 | $defaultPreferences['realname'] = [ |
||
| 289 | // (not really "private", but still shouldn't be edited without permission) |
||
| 290 | 'type' => $canEditPrivateInfo && $realnameChangeAllowed ? 'text' : 'info', |
||
| 291 | 'default' => $user->getRealName(), |
||
| 292 | 'section' => 'personal/info', |
||
| 293 | 'label-message' => 'yourrealname', |
||
| 294 | 'help-message' => 'prefs-help-realname', |
||
| 295 | ]; |
||
| 296 | |||
| 297 | $allowPasswordChange = $wgDisableAuthManager ? $wgAuth->allowPasswordChange() |
||
| 298 | : AuthManager::singleton()->allowsAuthenticationDataChange( |
||
| 299 | new PasswordAuthenticationRequest(), false ); |
||
| 300 | if ( $canEditPrivateInfo && $allowPasswordChange ) { |
||
| 301 | $link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ), |
||
| 302 | $context->msg( 'prefs-resetpass' )->escaped(), [], |
||
| 303 | [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] ); |
||
| 304 | |||
| 305 | $defaultPreferences['password'] = [ |
||
| 306 | 'type' => 'info', |
||
| 307 | 'raw' => true, |
||
| 308 | 'default' => $link, |
||
| 309 | 'label-message' => 'yourpassword', |
||
| 310 | 'section' => 'personal/info', |
||
| 311 | ]; |
||
| 312 | } |
||
| 313 | // Only show prefershttps if secure login is turned on |
||
| 314 | if ( $config->get( 'SecureLogin' ) && wfCanIPUseHTTPS( $context->getRequest()->getIP() ) ) { |
||
| 315 | $defaultPreferences['prefershttps'] = [ |
||
| 316 | 'type' => 'toggle', |
||
| 317 | 'label-message' => 'tog-prefershttps', |
||
| 318 | 'help-message' => 'prefs-help-prefershttps', |
||
| 319 | 'section' => 'personal/info' |
||
| 320 | ]; |
||
| 321 | } |
||
| 322 | |||
| 323 | // Language |
||
| 324 | $languages = Language::fetchLanguageNames( null, 'mw' ); |
||
| 325 | $languageCode = $config->get( 'LanguageCode' ); |
||
| 326 | if ( !array_key_exists( $languageCode, $languages ) ) { |
||
| 327 | $languages[$languageCode] = $languageCode; |
||
| 328 | } |
||
| 329 | ksort( $languages ); |
||
| 330 | |||
| 331 | $options = []; |
||
| 332 | foreach ( $languages as $code => $name ) { |
||
| 333 | $display = wfBCP47( $code ) . ' - ' . $name; |
||
| 334 | $options[$display] = $code; |
||
| 335 | } |
||
| 336 | $defaultPreferences['language'] = [ |
||
| 337 | 'type' => 'select', |
||
| 338 | 'section' => 'personal/i18n', |
||
| 339 | 'options' => $options, |
||
| 340 | 'label-message' => 'yourlanguage', |
||
| 341 | ]; |
||
| 342 | |||
| 343 | $defaultPreferences['gender'] = [ |
||
| 344 | 'type' => 'radio', |
||
| 345 | 'section' => 'personal/i18n', |
||
| 346 | 'options' => [ |
||
| 347 | $context->msg( 'parentheses' ) |
||
| 348 | ->params( $context->msg( 'gender-unknown' )->plain() ) |
||
| 349 | ->escaped() => 'unknown', |
||
| 350 | $context->msg( 'gender-female' )->escaped() => 'female', |
||
| 351 | $context->msg( 'gender-male' )->escaped() => 'male', |
||
| 352 | ], |
||
| 353 | 'label-message' => 'yourgender', |
||
| 354 | 'help-message' => 'prefs-help-gender', |
||
| 355 | ]; |
||
| 356 | |||
| 357 | // see if there are multiple language variants to choose from |
||
| 358 | if ( !$config->get( 'DisableLangConversion' ) ) { |
||
| 359 | foreach ( LanguageConverter::$languagesWithVariants as $langCode ) { |
||
| 360 | if ( $langCode == $wgContLang->getCode() ) { |
||
| 361 | $variants = $wgContLang->getVariants(); |
||
| 362 | |||
| 363 | if ( count( $variants ) <= 1 ) { |
||
| 364 | continue; |
||
| 365 | } |
||
| 366 | |||
| 367 | $variantArray = []; |
||
| 368 | foreach ( $variants as $v ) { |
||
| 369 | $v = str_replace( '_', '-', strtolower( $v ) ); |
||
| 370 | $variantArray[$v] = $lang->getVariantname( $v, false ); |
||
| 371 | } |
||
| 372 | |||
| 373 | $options = []; |
||
| 374 | foreach ( $variantArray as $code => $name ) { |
||
| 375 | $display = wfBCP47( $code ) . ' - ' . $name; |
||
| 376 | $options[$display] = $code; |
||
| 377 | } |
||
| 378 | |||
| 379 | $defaultPreferences['variant'] = [ |
||
| 380 | 'label-message' => 'yourvariant', |
||
| 381 | 'type' => 'select', |
||
| 382 | 'options' => $options, |
||
| 383 | 'section' => 'personal/i18n', |
||
| 384 | 'help-message' => 'prefs-help-variant', |
||
| 385 | ]; |
||
| 386 | } else { |
||
| 387 | $defaultPreferences["variant-$langCode"] = [ |
||
| 388 | 'type' => 'api', |
||
| 389 | ]; |
||
| 390 | } |
||
| 391 | } |
||
| 392 | } |
||
| 393 | |||
| 394 | // Stuff from Language::getExtraUserToggles() |
||
| 395 | // FIXME is this dead code? $extraUserToggles doesn't seem to be defined for any language |
||
| 396 | $toggles = $wgContLang->getExtraUserToggles(); |
||
| 397 | |||
| 398 | foreach ( $toggles as $toggle ) { |
||
| 399 | $defaultPreferences[$toggle] = [ |
||
| 400 | 'type' => 'toggle', |
||
| 401 | 'section' => 'personal/i18n', |
||
| 402 | 'label-message' => "tog-$toggle", |
||
| 403 | ]; |
||
| 404 | } |
||
| 405 | |||
| 406 | // show a preview of the old signature first |
||
| 407 | $oldsigWikiText = $wgParser->preSaveTransform( |
||
| 408 | '~~~', |
||
| 409 | $context->getTitle(), |
||
| 410 | $user, |
||
| 411 | ParserOptions::newFromContext( $context ) |
||
| 412 | ); |
||
| 413 | $oldsigHTML = $context->getOutput()->parseInline( $oldsigWikiText, true, true ); |
||
| 414 | $defaultPreferences['oldsig'] = [ |
||
| 415 | 'type' => 'info', |
||
| 416 | 'raw' => true, |
||
| 417 | 'label-message' => 'tog-oldsig', |
||
| 418 | 'default' => $oldsigHTML, |
||
| 419 | 'section' => 'personal/signature', |
||
| 420 | ]; |
||
| 421 | $nicknameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'nickname' ) |
||
| 422 | : AuthManager::singleton()->allowsPropertyChange( 'nickname' ); |
||
| 423 | $defaultPreferences['nickname'] = [ |
||
| 424 | 'type' => $nicknameChangeAllowed ? 'text' : 'info', |
||
| 425 | 'maxlength' => $config->get( 'MaxSigChars' ), |
||
| 426 | 'label-message' => 'yournick', |
||
| 427 | 'validation-callback' => [ 'Preferences', 'validateSignature' ], |
||
| 428 | 'section' => 'personal/signature', |
||
| 429 | 'filter-callback' => [ 'Preferences', 'cleanSignature' ], |
||
| 430 | ]; |
||
| 431 | $defaultPreferences['fancysig'] = [ |
||
| 432 | 'type' => 'toggle', |
||
| 433 | 'label-message' => 'tog-fancysig', |
||
| 434 | // show general help about signature at the bottom of the section |
||
| 435 | 'help-message' => 'prefs-help-signature', |
||
| 436 | 'section' => 'personal/signature' |
||
| 437 | ]; |
||
| 438 | |||
| 439 | # # Email stuff |
||
| 440 | |||
| 441 | if ( $config->get( 'EnableEmail' ) ) { |
||
| 442 | if ( $canViewPrivateInfo ) { |
||
| 443 | $helpMessages[] = $config->get( 'EmailConfirmToEdit' ) |
||
| 444 | ? 'prefs-help-email-required' |
||
| 445 | : 'prefs-help-email'; |
||
| 446 | |||
| 447 | if ( $config->get( 'EnableUserEmail' ) ) { |
||
| 448 | // additional messages when users can send email to each other |
||
| 449 | $helpMessages[] = 'prefs-help-email-others'; |
||
| 450 | } |
||
| 451 | |||
| 452 | $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : ''; |
||
| 453 | $emailChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'emailaddress' ) |
||
| 454 | : AuthManager::singleton()->allowsPropertyChange( 'emailaddress' ); |
||
| 455 | if ( $canEditPrivateInfo && $emailChangeAllowed ) { |
||
| 456 | $link = Linker::link( |
||
| 457 | SpecialPage::getTitleFor( 'ChangeEmail' ), |
||
| 458 | $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(), |
||
| 459 | [], |
||
| 460 | [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] ); |
||
| 461 | |||
| 462 | $emailAddress .= $emailAddress == '' ? $link : ( |
||
| 463 | $context->msg( 'word-separator' )->escaped() |
||
| 464 | . $context->msg( 'parentheses' )->rawParams( $link )->escaped() |
||
| 465 | ); |
||
| 466 | } |
||
| 467 | |||
| 468 | $defaultPreferences['emailaddress'] = [ |
||
| 469 | 'type' => 'info', |
||
| 470 | 'raw' => true, |
||
| 471 | 'default' => $emailAddress, |
||
| 472 | 'label-message' => 'youremail', |
||
| 473 | 'section' => 'personal/email', |
||
| 474 | 'help-messages' => $helpMessages, |
||
| 475 | # 'cssclass' chosen below |
||
| 476 | ]; |
||
| 477 | } |
||
| 478 | |||
| 479 | $disableEmailPrefs = false; |
||
| 480 | |||
| 481 | if ( $config->get( 'EmailAuthentication' ) ) { |
||
| 482 | $emailauthenticationclass = 'mw-email-not-authenticated'; |
||
| 483 | if ( $user->getEmail() ) { |
||
| 484 | if ( $user->getEmailAuthenticationTimestamp() ) { |
||
| 485 | // date and time are separate parameters to facilitate localisation. |
||
| 486 | // $time is kept for backward compat reasons. |
||
| 487 | // 'emailauthenticated' is also used in SpecialConfirmemail.php |
||
| 488 | $displayUser = $context->getUser(); |
||
| 489 | $emailTimestamp = $user->getEmailAuthenticationTimestamp(); |
||
| 490 | $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser ); |
||
| 491 | $d = $lang->userDate( $emailTimestamp, $displayUser ); |
||
| 492 | $t = $lang->userTime( $emailTimestamp, $displayUser ); |
||
| 493 | $emailauthenticated = $context->msg( 'emailauthenticated', |
||
| 494 | $time, $d, $t )->parse() . '<br />'; |
||
| 495 | $disableEmailPrefs = false; |
||
| 496 | $emailauthenticationclass = 'mw-email-authenticated'; |
||
| 497 | } else { |
||
| 498 | $disableEmailPrefs = true; |
||
| 499 | $emailauthenticated = $context->msg( 'emailnotauthenticated' )->parse() . '<br />' . |
||
| 500 | Linker::linkKnown( |
||
| 501 | SpecialPage::getTitleFor( 'Confirmemail' ), |
||
| 502 | $context->msg( 'emailconfirmlink' )->escaped() |
||
| 503 | ) . '<br />'; |
||
| 504 | $emailauthenticationclass = "mw-email-not-authenticated"; |
||
| 505 | } |
||
| 506 | } else { |
||
| 507 | $disableEmailPrefs = true; |
||
| 508 | $emailauthenticated = $context->msg( 'noemailprefs' )->escaped(); |
||
| 509 | $emailauthenticationclass = 'mw-email-none'; |
||
| 510 | } |
||
| 511 | |||
| 512 | if ( $canViewPrivateInfo ) { |
||
| 513 | $defaultPreferences['emailauthentication'] = [ |
||
| 514 | 'type' => 'info', |
||
| 515 | 'raw' => true, |
||
| 516 | 'section' => 'personal/email', |
||
| 517 | 'label-message' => 'prefs-emailconfirm-label', |
||
| 518 | 'default' => $emailauthenticated, |
||
| 519 | # Apply the same CSS class used on the input to the message: |
||
| 520 | 'cssclass' => $emailauthenticationclass, |
||
| 521 | ]; |
||
| 522 | } |
||
| 523 | } |
||
| 524 | |||
| 525 | if ( $config->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) { |
||
| 526 | $defaultPreferences['disablemail'] = [ |
||
| 527 | 'type' => 'toggle', |
||
| 528 | 'invert' => true, |
||
| 529 | 'section' => 'personal/email', |
||
| 530 | 'label-message' => 'allowemail', |
||
| 531 | 'disabled' => $disableEmailPrefs, |
||
| 532 | ]; |
||
| 533 | $defaultPreferences['ccmeonemails'] = [ |
||
| 534 | 'type' => 'toggle', |
||
| 535 | 'section' => 'personal/email', |
||
| 536 | 'label-message' => 'tog-ccmeonemails', |
||
| 537 | 'disabled' => $disableEmailPrefs, |
||
| 538 | ]; |
||
| 539 | } |
||
| 540 | |||
| 541 | View Code Duplication | if ( $config->get( 'EnotifWatchlist' ) ) { |
|
| 542 | $defaultPreferences['enotifwatchlistpages'] = [ |
||
| 543 | 'type' => 'toggle', |
||
| 544 | 'section' => 'personal/email', |
||
| 545 | 'label-message' => 'tog-enotifwatchlistpages', |
||
| 546 | 'disabled' => $disableEmailPrefs, |
||
| 547 | ]; |
||
| 548 | } |
||
| 549 | View Code Duplication | if ( $config->get( 'EnotifUserTalk' ) ) { |
|
| 550 | $defaultPreferences['enotifusertalkpages'] = [ |
||
| 551 | 'type' => 'toggle', |
||
| 552 | 'section' => 'personal/email', |
||
| 553 | 'label-message' => 'tog-enotifusertalkpages', |
||
| 554 | 'disabled' => $disableEmailPrefs, |
||
| 555 | ]; |
||
| 556 | } |
||
| 557 | if ( $config->get( 'EnotifUserTalk' ) || $config->get( 'EnotifWatchlist' ) ) { |
||
| 558 | View Code Duplication | if ( $config->get( 'EnotifMinorEdits' ) ) { |
|
| 559 | $defaultPreferences['enotifminoredits'] = [ |
||
| 560 | 'type' => 'toggle', |
||
| 561 | 'section' => 'personal/email', |
||
| 562 | 'label-message' => 'tog-enotifminoredits', |
||
| 563 | 'disabled' => $disableEmailPrefs, |
||
| 564 | ]; |
||
| 565 | } |
||
| 566 | |||
| 567 | View Code Duplication | if ( $config->get( 'EnotifRevealEditorAddress' ) ) { |
|
| 568 | $defaultPreferences['enotifrevealaddr'] = [ |
||
| 569 | 'type' => 'toggle', |
||
| 570 | 'section' => 'personal/email', |
||
| 571 | 'label-message' => 'tog-enotifrevealaddr', |
||
| 572 | 'disabled' => $disableEmailPrefs, |
||
| 573 | ]; |
||
| 574 | } |
||
| 575 | } |
||
| 576 | } |
||
| 577 | } |
||
| 578 | |||
| 579 | /** |
||
| 580 | * @param User $user |
||
| 581 | * @param IContextSource $context |
||
| 582 | * @param array $defaultPreferences |
||
| 583 | * @return void |
||
| 584 | */ |
||
| 585 | static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 628 | |||
| 629 | /** |
||
| 630 | * @param User $user |
||
| 631 | * @param IContextSource $context |
||
| 632 | * @param array $defaultPreferences |
||
| 633 | */ |
||
| 634 | static function filesPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 649 | |||
| 650 | /** |
||
| 651 | * @param User $user |
||
| 652 | * @param IContextSource $context |
||
| 653 | * @param array $defaultPreferences |
||
| 654 | * @return void |
||
| 655 | */ |
||
| 656 | static function datetimePreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 723 | |||
| 724 | /** |
||
| 725 | * @param User $user |
||
| 726 | * @param IContextSource $context |
||
| 727 | * @param array $defaultPreferences |
||
| 728 | */ |
||
| 729 | static function renderingPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 785 | |||
| 786 | /** |
||
| 787 | * @param User $user |
||
| 788 | * @param IContextSource $context |
||
| 789 | * @param array $defaultPreferences |
||
| 790 | */ |
||
| 791 | static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 871 | |||
| 872 | /** |
||
| 873 | * @param User $user |
||
| 874 | * @param IContextSource $context |
||
| 875 | * @param array $defaultPreferences |
||
| 876 | */ |
||
| 877 | static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 939 | |||
| 940 | /** |
||
| 941 | * @param User $user |
||
| 942 | * @param IContextSource $context |
||
| 943 | * @param array $defaultPreferences |
||
| 944 | */ |
||
| 945 | static function watchlistPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 1088 | |||
| 1089 | /** |
||
| 1090 | * @param User $user |
||
| 1091 | * @param IContextSource $context |
||
| 1092 | * @param array $defaultPreferences |
||
| 1093 | */ |
||
| 1094 | static function searchPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 1101 | |||
| 1102 | /** |
||
| 1103 | * Dummy, kept for backwards-compatibility. |
||
| 1104 | */ |
||
| 1105 | static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) { |
||
| 1107 | |||
| 1108 | /** |
||
| 1109 | * @param User $user The User object |
||
| 1110 | * @param IContextSource $context |
||
| 1111 | * @return array Text/links to display as key; $skinkey as value |
||
| 1112 | */ |
||
| 1113 | static function generateSkinOptions( $user, IContextSource $context ) { |
||
| 1176 | |||
| 1177 | /** |
||
| 1178 | * @param IContextSource $context |
||
| 1179 | * @return array |
||
| 1180 | */ |
||
| 1181 | static function getDateOptions( IContextSource $context ) { |
||
| 1211 | |||
| 1212 | /** |
||
| 1213 | * @param IContextSource $context |
||
| 1214 | * @return array |
||
| 1215 | */ |
||
| 1216 | static function getImageSizes( IContextSource $context ) { |
||
| 1227 | |||
| 1228 | /** |
||
| 1229 | * @param IContextSource $context |
||
| 1230 | * @return array |
||
| 1231 | */ |
||
| 1232 | static function getThumbSizes( IContextSource $context ) { |
||
| 1243 | |||
| 1244 | /** |
||
| 1245 | * @param string $signature |
||
| 1246 | * @param array $alldata |
||
| 1247 | * @param HTMLForm $form |
||
| 1248 | * @return bool|string |
||
| 1249 | */ |
||
| 1250 | static function validateSignature( $signature, $alldata, $form ) { |
||
| 1269 | |||
| 1270 | /** |
||
| 1271 | * @param string $signature |
||
| 1272 | * @param array $alldata |
||
| 1273 | * @param HTMLForm $form |
||
| 1274 | * @return string |
||
| 1275 | */ |
||
| 1276 | static function cleanSignature( $signature, $alldata, $form ) { |
||
| 1287 | |||
| 1288 | /** |
||
| 1289 | * @param User $user |
||
| 1290 | * @param IContextSource $context |
||
| 1291 | * @param string $formClass |
||
| 1292 | * @param array $remove Array of items to remove |
||
| 1293 | * @return PreferencesForm|HtmlForm |
||
| 1294 | */ |
||
| 1295 | static function getFormObject( |
||
| 1330 | |||
| 1331 | /** |
||
| 1332 | * @param IContextSource $context |
||
| 1333 | * @return array |
||
| 1334 | */ |
||
| 1335 | static function getTimezoneOptions( IContextSource $context ) { |
||
| 1374 | |||
| 1375 | /** |
||
| 1376 | * @param string $value |
||
| 1377 | * @param array $alldata |
||
| 1378 | * @return int |
||
| 1379 | */ |
||
| 1380 | static function filterIntval( $value, $alldata ) { |
||
| 1383 | |||
| 1384 | /** |
||
| 1385 | * @param string $tz |
||
| 1386 | * @param array $alldata |
||
| 1387 | * @return string |
||
| 1388 | */ |
||
| 1389 | static function filterTimezoneInput( $tz, $alldata ) { |
||
| 1415 | |||
| 1416 | /** |
||
| 1417 | * Handle the form submission if everything validated properly |
||
| 1418 | * |
||
| 1419 | * @param array $formData |
||
| 1420 | * @param PreferencesForm $form |
||
| 1421 | * @return bool|Status|string |
||
| 1422 | */ |
||
| 1423 | static function tryFormSubmit( $formData, $form ) { |
||
| 1424 | $user = $form->getModifiedUser(); |
||
| 1425 | $hiddenPrefs = $form->getConfig()->get( 'HiddenPrefs' ); |
||
| 1426 | $result = true; |
||
| 1427 | |||
| 1428 | if ( !$user->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) { |
||
| 1429 | return Status::newFatal( 'mypreferencesprotected' ); |
||
| 1430 | } |
||
| 1431 | |||
| 1432 | // Filter input |
||
| 1433 | foreach ( array_keys( $formData ) as $name ) { |
||
| 1434 | if ( isset( self::$saveFilters[$name] ) ) { |
||
| 1435 | $formData[$name] = |
||
| 1436 | call_user_func( self::$saveFilters[$name], $formData[$name], $formData ); |
||
| 1437 | } |
||
| 1438 | } |
||
| 1439 | |||
| 1440 | // Fortunately, the realname field is MUCH simpler |
||
| 1441 | // (not really "private", but still shouldn't be edited without permission) |
||
| 1442 | |||
| 1443 | if ( !in_array( 'realname', $hiddenPrefs ) |
||
| 1444 | && $user->isAllowed( 'editmyprivateinfo' ) |
||
| 1445 | && array_key_exists( 'realname', $formData ) |
||
| 1446 | ) { |
||
| 1447 | $realName = $formData['realname']; |
||
| 1448 | $user->setRealName( $realName ); |
||
| 1449 | } |
||
| 1450 | |||
| 1451 | if ( $user->isAllowed( 'editmyoptions' ) ) { |
||
| 1452 | foreach ( self::$saveBlacklist as $b ) { |
||
| 1453 | unset( $formData[$b] ); |
||
| 1454 | } |
||
| 1455 | |||
| 1456 | # If users have saved a value for a preference which has subsequently been disabled |
||
| 1457 | # via $wgHiddenPrefs, we don't want to destroy that setting in case the preference |
||
| 1458 | # is subsequently re-enabled |
||
| 1459 | foreach ( $hiddenPrefs as $pref ) { |
||
| 1460 | # If the user has not set a non-default value here, the default will be returned |
||
| 1461 | # and subsequently discarded |
||
| 1462 | $formData[$pref] = $user->getOption( $pref, null, true ); |
||
| 1463 | } |
||
| 1464 | |||
| 1465 | // Keep old preferences from interfering due to back-compat code, etc. |
||
| 1466 | $user->resetOptions( 'unused', $form->getContext() ); |
||
| 1467 | |||
| 1468 | foreach ( $formData as $key => $value ) { |
||
| 1469 | $user->setOption( $key, $value ); |
||
| 1470 | } |
||
| 1471 | |||
| 1472 | Hooks::run( 'PreferencesFormPreSave', [ $formData, $form, $user, &$result ] ); |
||
| 1473 | } |
||
| 1474 | |||
| 1475 | MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'updateExternalDB', [ $user ] ); |
||
| 1476 | $user->saveSettings(); |
||
| 1477 | |||
| 1478 | return $result; |
||
| 1479 | } |
||
| 1480 | |||
| 1481 | /** |
||
| 1482 | * @param array $formData |
||
| 1483 | * @param PreferencesForm $form |
||
| 1484 | * @return Status |
||
| 1485 | */ |
||
| 1486 | public static function tryUISubmit( $formData, $form ) { |
||
| 1509 | |||
| 1510 | /** |
||
| 1511 | * Get a list of all time zones |
||
| 1512 | * @param Language $language Language used for the localized names |
||
| 1513 | * @return array A list of all time zones. The system name of the time zone is used as key and |
||
| 1514 | * the value is an array which contains localized name, the timecorrection value used for |
||
| 1515 | * preferences and the region |
||
| 1516 | * @since 1.26 |
||
| 1517 | */ |
||
| 1518 | public static function getTimeZoneList( Language $language ) { |
||
| 1571 | } |
||
| 1572 | |||
| 1573 | /** Some tweaks to allow js prefs to work */ |
||
| 1692 |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
stringvalues, the empty string''is a special case, in particular the following results might be unexpected: