r33333 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r33332‎ | r33333 | r33334 >
Date:09:04, 15 April 2008
Author:tstarling
Status:old
Tags:
Comment:
In User:
* Defer load of groups data
* Introduce newFromRow()/loadFromRow() to allow bulk loading of user objects from a result set
* Hook email and email authentication save/load to allow CentralAuth to provide a global email address
* Defer save of user data after confirmEmail() and invalidateEmail(). Caller must now also call saveSettings(). This reduces the master query count in some code paths.

Elsewhere:
* Introduce UserArray class, for bulk loading of user objects. Immediately useful in email notification, potentially useful for proposed user alias feature.
* In Special:Confirmemail, remove useless handling for impossible false return from confirmEmail()/invalidateEmail().
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/SpecialConfirmemail.php (modified) (history)
  • /trunk/phase3/includes/SpecialPreferences.php (modified) (history)
  • /trunk/phase3/includes/SpecialUserlogin.php (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/includes/UserArray.php (added) (history)
  • /trunk/phase3/includes/UserMailer.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/User.php
@@ -206,7 +206,6 @@
207207 # Can't load from ID, user is anonymous
208208 return false;
209209 }
210 -
211210 $this->saveToCache();
212211 } else {
213212 wfDebug( "Got user {$this->mId} from cache\n" );
@@ -223,6 +222,7 @@
224223 */
225224 function saveToCache() {
226225 $this->load();
 226+ $this->loadGroups();
227227 if ( $this->isAnon() ) {
228228 // Anonymous users are uncached
229229 return;
@@ -314,6 +314,16 @@
315315 }
316316
317317 /**
 318+ * Create a new user object from a user row.
 319+ * The row should have all fields from the user table in it.
 320+ */
 321+ static function newFromRow( $row ) {
 322+ $user = new User;
 323+ $user->loadFromRow( $row );
 324+ return $user;
 325+ }
 326+
 327+ /**
318328 * Get username given an id.
319329 * @param integer $id Database user id
320330 * @return string Nickname of a user
@@ -788,23 +798,50 @@
789799
790800 if ( $s !== false ) {
791801 # Initialise user table data
792 - $this->mName = $s->user_name;
793 - $this->mRealName = $s->user_real_name;
794 - $this->mPassword = $s->user_password;
795 - $this->mNewpassword = $s->user_newpassword;
796 - $this->mNewpassTime = wfTimestampOrNull( TS_MW, $s->user_newpass_time );
797 - $this->mEmail = $s->user_email;
798 - $this->decodeOptions( $s->user_options );
799 - $this->mTouched = wfTimestamp(TS_MW,$s->user_touched);
800 - $this->mToken = $s->user_token;
801 - $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $s->user_email_authenticated );
802 - $this->mEmailToken = $s->user_email_token;
803 - $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $s->user_email_token_expires );
804 - $this->mRegistration = wfTimestampOrNull( TS_MW, $s->user_registration );
805 - $this->mEditCount = $s->user_editcount;
 802+ $this->loadFromRow( $s );
 803+ $this->mGroups = null; // deferred
806804 $this->getEditCount(); // revalidation for nulls
 805+ return true;
 806+ } else {
 807+ # Invalid user_id
 808+ $this->mId = 0;
 809+ $this->loadDefaults();
 810+ return false;
 811+ }
 812+ }
807813
808 - # Load group data
 814+ /**
 815+ * Initialise the user object from a row from the user table
 816+ */
 817+ function loadFromRow( $row ) {
 818+ $this->mDataLoaded = true;
 819+
 820+ if ( isset( $row->user_id ) ) {
 821+ $this->mId = $row->user_id;
 822+ }
 823+ $this->mName = $row->user_name;
 824+ $this->mRealName = $row->user_real_name;
 825+ $this->mPassword = $row->user_password;
 826+ $this->mNewpassword = $row->user_newpassword;
 827+ $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
 828+ $this->mEmail = $row->user_email;
 829+ $this->decodeOptions( $row->user_options );
 830+ $this->mTouched = wfTimestamp(TS_MW,$row->user_touched);
 831+ $this->mToken = $row->user_token;
 832+ $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
 833+ $this->mEmailToken = $row->user_email_token;
 834+ $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
 835+ $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
 836+ $this->mEditCount = $row->user_editcount;
 837+ }
 838+
 839+ /**
 840+ * Load the groups from the database if they aren't already loaded
 841+ * @private
 842+ */
 843+ function loadGroups() {
 844+ if ( is_null( $this->mGroups ) ) {
 845+ $dbr = wfGetDB( DB_MASTER );
809846 $res = $dbr->select( 'user_groups',
810847 array( 'ug_group' ),
811848 array( 'ug_user' => $this->mId ),
@@ -813,12 +850,6 @@
814851 while( $row = $dbr->fetchObject( $res ) ) {
815852 $this->mGroups[] = $row->ug_group;
816853 }
817 - return true;
818 - } else {
819 - # Invalid user_id
820 - $this->mId = 0;
821 - $this->loadDefaults();
822 - return false;
823854 }
824855 }
825856
@@ -1529,17 +1560,20 @@
15301561
15311562 function getEmail() {
15321563 $this->load();
 1564+ wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) );
15331565 return $this->mEmail;
15341566 }
15351567
15361568 function getEmailAuthenticationTimestamp() {
15371569 $this->load();
 1570+ wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
15381571 return $this->mEmailAuthenticated;
15391572 }
15401573
15411574 function setEmail( $str ) {
15421575 $this->load();
15431576 $this->mEmail = $str;
 1577+ wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) );
15441578 }
15451579
15461580 function getRealName() {
@@ -1657,10 +1691,9 @@
16581692 */
16591693 function getEffectiveGroups( $recache = false ) {
16601694 if ( $recache || is_null( $this->mEffectiveGroups ) ) {
1661 - $this->load();
1662 - $this->mEffectiveGroups = $this->mGroups;
 1695+ $this->mEffectiveGroups = $this->getGroups();
16631696 $this->mEffectiveGroups[] = '*';
1664 - if( $this->mId ) {
 1697+ if( $this->getId() ) {
16651698 $this->mEffectiveGroups[] = 'user';
16661699
16671700 $this->mEffectiveGroups = array_unique( array_merge(
@@ -1695,7 +1728,6 @@
16961729 * @param string $group
16971730 */
16981731 function addGroup( $group ) {
1699 - $this->load();
17001732 $dbw = wfGetDB( DB_MASTER );
17011733 if( $this->getId() ) {
17021734 $dbw->insert( 'user_groups',
@@ -1707,6 +1739,7 @@
17081740 array( 'IGNORE' ) );
17091741 }
17101742
 1743+ $this->loadGroups();
17111744 $this->mGroups[] = $group;
17121745 $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) );
17131746
@@ -1728,6 +1761,7 @@
17291762 ),
17301763 'User::removeGroup' );
17311764
 1765+ $this->loadGroups();
17321766 $this->mGroups = array_diff( $this->mGroups, array( $group ) );
17331767 $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) );
17341768
@@ -2044,10 +2078,10 @@
20452079 'user_id' => $this->mId
20462080 ), __METHOD__
20472081 );
 2082+ wfRunHooks( 'UserSaveSettings', array( $this ) );
20482083 $this->clearSharedCache();
20492084 }
20502085
2051 -
20522086 /**
20532087 * Checks if a user with the given name exists, returns the ID.
20542088 */
@@ -2398,6 +2432,9 @@
23992433 * Generate a new e-mail confirmation token and send a confirmation/invalidation
24002434 * mail to the user's given address.
24012435 *
 2436+ * Call saveSettings() after calling this function to commit the confirmation
 2437+ * token to the database.
 2438+ *
24022439 * @return mixed True on success, a WikiError object on failure.
24032440 */
24042441 function sendConfirmationMail() {
@@ -2438,6 +2475,10 @@
24392476 /**
24402477 * Generate, store, and return a new e-mail confirmation code.
24412478 * A hash (unsalted since it's used as a key) is stored.
 2479+ *
 2480+ * Call saveSettings() after calling this function to commit
 2481+ * this change to the database.
 2482+ *
24422483 * @param &$expiration mixed output: accepts the expiration time
24432484 * @return string
24442485 * @private
@@ -2451,7 +2492,6 @@
24522493 $this->load();
24532494 $this->mEmailToken = $hash;
24542495 $this->mEmailTokenExpires = $expiration;
2455 - $this->saveSettings();
24562496 return $token;
24572497 }
24582498
@@ -2477,28 +2517,35 @@
24782518 }
24792519
24802520 /**
2481 - * Mark the e-mail address confirmed and save.
 2521+ * Mark the e-mail address confirmed.
 2522+ *
 2523+ * Call saveSettings() after calling this function to commit the change.
24822524 */
24832525 function confirmEmail() {
2484 - $this->load();
2485 - $this->mEmailAuthenticated = wfTimestampNow();
2486 - $this->saveSettings();
 2526+ $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
24872527 return true;
24882528 }
24892529
24902530 /**
24912531 * Invalidate the user's email confirmation, unauthenticate the email
2492 - * if it was already confirmed and save.
 2532+ * if it was already confirmed.
 2533+ *
 2534+ * Call saveSettings() after calling this function to commit the change.
24932535 */
24942536 function invalidateEmail() {
24952537 $this->load();
24962538 $this->mEmailToken = null;
24972539 $this->mEmailTokenExpires = null;
2498 - $this->mEmailAuthenticated = null;
2499 - $this->saveSettings();
 2540+ $this->setEmailAuthenticationTimestamp( null );
25002541 return true;
25012542 }
25022543
 2544+ function setEmailAuthenticationTimestamp( $timestamp ) {
 2545+ $this->load();
 2546+ $this->mEmailAuthenticated = $timestamp;
 2547+ wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
 2548+ }
 2549+
25032550 /**
25042551 * Is this user allowed to send e-mails within limits of current
25052552 * site configuration?
Index: trunk/phase3/includes/SpecialUserlogin.php
@@ -158,8 +158,7 @@
159159 if( $wgLoginLanguageSelector && $this->mLanguage )
160160 $u->setOption( 'language', $this->mLanguage );
161161
162 - # Save user settings and send out an email authentication message if needed
163 - $u->saveSettings();
 162+ # Send out an email authentication message if needed
164163 if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
165164 global $wgOut;
166165 $error = $u->sendConfirmationMail();
@@ -170,6 +169,9 @@
171170 }
172171 }
173172
 173+ # Save settings (including confirmation token)
 174+ $u->saveSettings();
 175+
174176 # If not logged in, assume the new account as the current one and set session cookies
175177 # then show a "welcome" message or a "need cookies" message as needed
176178 if( $wgUser->isAnon() ) {
@@ -420,6 +422,7 @@
421423 //
422424 if( !$u->isEmailConfirmed() ) {
423425 $u->confirmEmail();
 426+ $u->saveSettings();
424427 }
425428
426429 // At this point we just return an appropriate code
Index: trunk/phase3/includes/UserMailer.php
@@ -362,16 +362,17 @@
363363 }
364364 $dbr = wfGetDB( DB_SLAVE );
365365
366 - $res = $dbr->select( 'watchlist', array( 'wl_user' ),
 366+ $res = $dbr->select( array( 'watchlist', 'user' ), array( 'user.*' ),
367367 array(
 368+ 'wl_user=user_id',
368369 'wl_title' => $title->getDBkey(),
369370 'wl_namespace' => $title->getNamespace(),
370371 $userCondition,
371372 'wl_notificationtimestamp IS NULL',
372373 ), __METHOD__ );
 374+ $userArray = UserArray::newFromResult( $res );
373375
374 - foreach ( $res as $row ) {
375 - $watchingUser = User::newFromId( $row->wl_user );
 376+ foreach ( $userArray as $watchingUser ) {
376377 if ( $watchingUser->getOption( 'enotifwatchlistpages' ) &&
377378 ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) &&
378379 $watchingUser->isEmailConfirmed() )
Index: trunk/phase3/includes/SpecialConfirmemail.php
@@ -84,15 +84,13 @@
8585 global $wgUser, $wgOut;
8686 $user = User::newFromConfirmationCode( $code );
8787 if( is_object( $user ) ) {
88 - if( $user->confirmEmail() ) {
89 - $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
90 - $wgOut->addWikiMsg( $message );
91 - if( !$wgUser->isLoggedIn() ) {
92 - $title = SpecialPage::getTitleFor( 'Userlogin' );
93 - $wgOut->returnToMain( true, $title->getPrefixedText() );
94 - }
95 - } else {
96 - $wgOut->addWikiMsg( 'confirmemail_error' );
 88+ $user->confirmEmail();
 89+ $user->saveSettings();
 90+ $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
 91+ $wgOut->addWikiMsg( $message );
 92+ if( !$wgUser->isLoggedIn() ) {
 93+ $title = SpecialPage::getTitleFor( 'Userlogin' );
 94+ $wgOut->returnToMain( true, $title->getPrefixedText() );
9795 }
9896 } else {
9997 $wgOut->addWikiMsg( 'confirmemail_invalid' );
@@ -129,13 +127,10 @@
130128 $user = User::newFromConfirmationCode( $code );
131129 if( is_object( $user ) ) {
132130 $user->invalidateEmail();
133 - if( $user->invalidateEmail() ) {
134 - $wgOut->addWikiMsg( 'confirmemail_invalidated' );
135 - if( !$wgUser->isLoggedIn() ) {
136 - $wgOut->returnToMain();
137 - }
138 - } else {
139 - $wgOut->addWikiMsg( 'confirmemail_error' );
 131+ $user->saveSettings();
 132+ $wgOut->addWikiMsg( 'confirmemail_invalidated' );
 133+ if( !$wgUser->isLoggedIn() ) {
 134+ $wgOut->returnToMain();
140135 }
141136 } else {
142137 $wgOut->addWikiMsg( 'confirmemail_invalid' );
Index: trunk/phase3/includes/AutoLoader.php
@@ -266,6 +266,7 @@
267267 'UploadForm' => 'includes/SpecialUpload.php',
268268 'UploadFormMogile' => 'includes/SpecialUploadMogile.php',
269269 'User' => 'includes/User.php',
 270+ 'UserArray' => 'includes/UserArray.php',
270271 'UserMailer' => 'includes/UserMailer.php',
271272 'UserrightsPage' => 'includes/SpecialUserrights.php',
272273 'UserRightsProxy' => 'includes/UserRightsProxy.php',
Index: trunk/phase3/includes/SpecialPreferences.php
@@ -310,8 +310,10 @@
311311 if( ($newadr != '') && ($newadr != $oldadr) ) {
312312 # the user has supplied a new email address on the login page
313313 if( $wgUser->isValidEmailAddr( $newadr ) ) {
314 - $wgUser->mEmail = $newadr; # new behaviour: set this new emailaddr from login-page into user database record
315 - $wgUser->mEmailAuthenticated = null; # but flag as "dirty" = unauthenticated
 314+ # new behaviour: set this new emailaddr from login-page into user database record
 315+ $wgUser->setEmail( $newadr );
 316+ # but flag as "dirty" = unauthenticated
 317+ $wgUser->invalidateEmail();
316318 if ($wgEmailAuthentication) {
317319 # Mail a temporary password to the dirty address.
318320 # User can come back through the confirmation URL to re-enable email.
Index: trunk/phase3/includes/UserArray.php
@@ -0,0 +1,62 @@
 2+<?php
 3+
 4+abstract class UserArray implements Iterator {
 5+ static function newFromResult( $res ) {
 6+ $userArray = null;
 7+ if ( !wfRunHooks( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
 8+ return null;
 9+ }
 10+ if ( $userArray === null ) {
 11+ $userArray = self::newFromResult_internal( $res );
 12+ }
 13+ return $userArray;
 14+ }
 15+
 16+ protected static function newFromResult_internal( $res ) {
 17+ $userArray = new UserArrayFromResult( $res );
 18+ return $userArray;
 19+ }
 20+}
 21+
 22+class UserArrayFromResult extends UserArray {
 23+ var $res;
 24+ var $key, $current;
 25+
 26+ function __construct( $res ) {
 27+ $this->res = $res;
 28+ $this->key = 0;
 29+ $this->setCurrent( $this->res->current() );
 30+ }
 31+
 32+ protected function setCurrent( $row ) {
 33+ if ( $row === false ) {
 34+ $this->current = false;
 35+ } else {
 36+ $this->current = User::newFromRow( $row );
 37+ }
 38+ }
 39+
 40+ function current() {
 41+ return $this->current;
 42+ }
 43+
 44+ function key() {
 45+ return $this->key;
 46+ }
 47+
 48+ function next() {
 49+ $row = $this->res->next();
 50+ $this->setCurrent( $row );
 51+ $this->key++;
 52+ }
 53+
 54+ function rewind() {
 55+ $this->res->rewind();
 56+ $this->key = 0;
 57+ $this->setCurrent( $this->res->current() );
 58+ }
 59+
 60+ function valid() {
 61+ return $this->current !== false;
 62+ }
 63+}
Property changes on: trunk/phase3/includes/UserArray.php
___________________________________________________________________
Added: svn:eol-style
164 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r97795Fixed User::getGroups(), apparently broken since r33333. User::load() doesn't...tstarling06:17, 22 September 2011

Status & tagging log