+ protected function loadOptions() {
+ $this->load();
+ if ( $this->mOptionsLoaded || !$this->getId() )
+ return;
+
+ $this->mOptions = self::getDefaultOptions();
+
+ // Maybe load from the object
+ if ( !is_null( $this->mOptionOverrides ) ) {
+ wfDebug( "Loading options for user " . $this->getId() . " from override cache.\n" );
+ foreach( $this->mOptionOverrides as $key => $value ) {
+ $this->mOptions[$key] = $value;
+ }
+ } else {
+ wfDebug( "Loading options for user " . $this->getId() . " from database.\n" );
+ // Load from database
+ $dbr = wfGetDB( DB_SLAVE );
+
+ $res = $dbr->select(
+ 'user_properties',
+ '*',
+ array( 'up_user' => $this->getId() ),
+ __METHOD__
+ );
+
+ while( $row = $dbr->fetchObject( $res ) ) {
+ $this->mOptionOverrides[$row->up_property] = $row->up_value;
+ $this->mOptions[$row->up_property] = $row->up_value;
+ }
+ }
+
+ $this->mOptionsLoaded = true;
+
+ wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
+ }
+
+ protected function saveOptions() {
+ global $wgAllowPrefChange;
+
+ $extuser = ExternalUser::newFromUser( $this );
+
+ $this->loadOptions();
+ $dbw = wfGetDB( DB_MASTER );
+
+ $insert_rows = array();
+
+ $saveOptions = $this->mOptions;
+
+ // Allow hooks to abort, for instance to save to a global profile.
+ // Reset options to default state before saving.
+ if( !wfRunHooks( 'UserSaveOptions', array( $this, &$saveOptions ) ) )
+ return;
+
+ foreach( $saveOptions as $key => $value ) {
+ # Don't bother storing default values
+ if ( ( is_null( self::getDefaultOption( $key ) ) &&
+ !( $value === false || is_null($value) ) ) ||
+ $value != self::getDefaultOption( $key ) ) {
+ $insert_rows[] = array(
+ 'up_user' => $this->getId(),
+ 'up_property' => $key,
+ 'up_value' => $value,
+ );
+ }
+ if ( $extuser && isset( $wgAllowPrefChange[$key] ) ) {
+ switch ( $wgAllowPrefChange[$key] ) {
+ case 'local':
+ case 'message':
+ break;
+ case 'semiglobal':
+ case 'global':
+ $extuser->setPref( $key, $value );
+ }
+ }
+ }
+
+ $dbw->begin();
+ $dbw->delete( 'user_properties', array( 'up_user' => $this->getId() ), __METHOD__ );
+ $dbw->insert( 'user_properties', $insert_rows, __METHOD__ );
+ $dbw->commit();
+ }
+
+ /**
+ * Provide an array of HTML5 attributes to put on an input element
+ * intended for the user to enter a new password. This may include
+ * required, title, and/or pattern, depending on $wgMinimalPasswordLength.
+ *
+ * Do *not* use this when asking the user to enter his current password!
+ * Regardless of configuration, users may have invalid passwords for whatever
+ * reason (e.g., they were set before requirements were tightened up).
+ * Only use it when asking for a new password, like on account creation or
+ * ResetPass.
+ *
+ * Obviously, you still need to do server-side checking.
+ *
+ * @return array Array of HTML attributes suitable for feeding to
+ * Html::element(), directly or indirectly. (Don't feed to Xml::*()!
+ * That will potentially output invalid XHTML 1.0 Transitional, and will
+ * get confused by the boolean attribute syntax used.)
+ */
+ public static function passwordChangeInputAttribs() {
+ global $wgMinimalPasswordLength;
+
+ if ( $wgMinimalPasswordLength == 0 ) {
+ return array();
+ }
+
+ # Note that the pattern requirement will always be satisfied if the
+ # input is empty, so we need required in all cases.
+ $ret = array( 'required' );
+
+ # We can't actually do this right now, because Opera 9.6 will print out
+ # the entered password visibly in its error message! When other
+ # browsers add support for this attribute, or Opera fixes its support,
+ # we can add support with a version check to avoid doing this on Opera
+ # versions where it will be a problem. Reported to Opera as
+ # DSK-262266, but they don't have a public bug tracker for us to follow.
+ /*
+ if ( $wgMinimalPasswordLength > 1 ) {
+ $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
+ $ret['title'] = wfMsgExt( 'passwordtooshort', 'parsemag',
+ $wgMinimalPasswordLength );
+ }
+ */
+
+ return $ret;
+ }