Index: trunk/phase3/includes/User.php |
— | — | @@ -157,10 +157,13 @@ |
158 | 158 | /** |
159 | 159 | * Bool Whether the cache variables have been loaded. |
160 | 160 | */ |
161 | | - var $mDataLoaded, $mAuthLoaded, $mOptionsLoaded; |
| 161 | + //@{ |
| 162 | + var $mOptionsLoaded; |
| 163 | + private $mLoadedItems = array(); |
| 164 | + //@} |
162 | 165 | |
163 | 166 | /** |
164 | | - * String Initialization data source if mDataLoaded==false. May be one of: |
| 167 | + * String Initialization data source if mLoadedItems!==true. May be one of: |
165 | 168 | * - 'defaults' anonymous user initialised from class defaults |
166 | 169 | * - 'name' initialise from mName |
167 | 170 | * - 'id' initialise from mId |
— | — | @@ -211,13 +214,13 @@ |
212 | 215 | * Load the user table data for this object from the source given by mFrom. |
213 | 216 | */ |
214 | 217 | function load() { |
215 | | - if ( $this->mDataLoaded ) { |
| 218 | + if ( $this->mLoadedItems === true ) { |
216 | 219 | return; |
217 | 220 | } |
218 | 221 | wfProfileIn( __METHOD__ ); |
219 | 222 | |
220 | 223 | # Set it now to avoid infinite recursion in accessors |
221 | | - $this->mDataLoaded = true; |
| 224 | + $this->mLoadedItems = true; |
222 | 225 | |
223 | 226 | switch ( $this->mFrom ) { |
224 | 227 | case 'defaults': |
— | — | @@ -336,6 +339,7 @@ |
337 | 340 | $u = new User; |
338 | 341 | $u->mName = $name; |
339 | 342 | $u->mFrom = 'name'; |
| 343 | + $u->setItemLoaded( 'name' ); |
340 | 344 | return $u; |
341 | 345 | } |
342 | 346 | } |
— | — | @@ -350,6 +354,7 @@ |
351 | 355 | $u = new User; |
352 | 356 | $u->mId = $id; |
353 | 357 | $u->mFrom = 'id'; |
| 358 | + $u->setItemLoaded( 'id' ); |
354 | 359 | return $u; |
355 | 360 | } |
356 | 361 | |
— | — | @@ -390,7 +395,14 @@ |
391 | 396 | |
392 | 397 | /** |
393 | 398 | * Create a new user object from a user row. |
394 | | - * The row should have all fields from the user table in it. |
| 399 | + * The row should have the following fields from the user table in it: |
| 400 | + * - either user_name or user_id to load further data if needed (or both) |
| 401 | + * - user_real_name |
| 402 | + * - all other fields (email, password, etc.) |
| 403 | + * It is useless to provide the remaining fields if either user_id, |
| 404 | + * user_name and user_real_name are not provided because the whole row |
| 405 | + * will be loaded once more from the database when accessing them. |
| 406 | + * |
395 | 407 | * @param $row Array A row from the user table |
396 | 408 | * @return User |
397 | 409 | */ |
— | — | @@ -847,6 +859,31 @@ |
848 | 860 | } |
849 | 861 | |
850 | 862 | /** |
| 863 | + * Return whether an item has been loaded. |
| 864 | + * |
| 865 | + * @param $item String: item to check. Current possibilities: |
| 866 | + * - 'id' |
| 867 | + * - name |
| 868 | + * - realname |
| 869 | + * @return Boolean |
| 870 | + */ |
| 871 | + public function isItemLoaded( $item ) { |
| 872 | + return $this->mLoadedItems === true || ( isset( $this->mLoadedItems[$item] ) |
| 873 | + && $this->mLoadedItems[$item] === true ); |
| 874 | + } |
| 875 | + |
| 876 | + /** |
| 877 | + * Set that an item has been loaded |
| 878 | + * |
| 879 | + * @param $item String |
| 880 | + */ |
| 881 | + private function setItemLoaded( $item ) { |
| 882 | + if ( is_array( $this->mLoadedItems ) ) { |
| 883 | + $this->mLoadedItems[$item] = true; |
| 884 | + } |
| 885 | + } |
| 886 | + |
| 887 | + /** |
851 | 888 | * Load user data from the session or login cookie. If there are no valid |
852 | 889 | * credentials, initialises the user as an anonymous user. |
853 | 890 | * @return Bool True if the user is logged in, false otherwise. |
— | — | @@ -936,7 +973,7 @@ |
937 | 974 | |
938 | 975 | /** |
939 | 976 | * Load user and user_group data from the database. |
940 | | - * $this::mId must be set, this is how the user is identified. |
| 977 | + * $this->mId must be set, this is how the user is identified. |
941 | 978 | * |
942 | 979 | * @return Bool True if the user exists, false if the user is anonymous |
943 | 980 | * @private |
— | — | @@ -976,25 +1013,51 @@ |
977 | 1014 | * @param $row Array Row from the user table to load. |
978 | 1015 | */ |
979 | 1016 | function loadFromRow( $row ) { |
980 | | - $this->mDataLoaded = true; |
| 1017 | + $all = true; |
981 | 1018 | |
| 1019 | + if ( isset( $row->user_name ) ) { |
| 1020 | + $this->mName = $row->user_name; |
| 1021 | + $this->mFrom = 'name'; |
| 1022 | + $this->setItemLoaded( 'name' ); |
| 1023 | + } else { |
| 1024 | + $all = false; |
| 1025 | + } |
| 1026 | + |
| 1027 | + if ( isset( $row->user_name ) ) { |
| 1028 | + $this->mRealName = $row->user_real_name; |
| 1029 | + $this->setItemLoaded( 'realname' ); |
| 1030 | + } else { |
| 1031 | + $all = false; |
| 1032 | + } |
| 1033 | + |
982 | 1034 | if ( isset( $row->user_id ) ) { |
983 | 1035 | $this->mId = intval( $row->user_id ); |
| 1036 | + $this->mFrom = 'id'; |
| 1037 | + $this->setItemLoaded( 'id' ); |
| 1038 | + } else { |
| 1039 | + $all = false; |
984 | 1040 | } |
985 | | - $this->mName = $row->user_name; |
986 | | - $this->mRealName = $row->user_real_name; |
987 | | - $this->mPassword = $row->user_password; |
988 | | - $this->mNewpassword = $row->user_newpassword; |
989 | | - $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time ); |
990 | | - $this->mEmail = $row->user_email; |
991 | | - $this->decodeOptions( $row->user_options ); |
992 | | - $this->mTouched = wfTimestamp(TS_MW,$row->user_touched); |
993 | | - $this->mToken = $row->user_token; |
994 | | - $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated ); |
995 | | - $this->mEmailToken = $row->user_email_token; |
996 | | - $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires ); |
997 | | - $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration ); |
998 | | - $this->mEditCount = $row->user_editcount; |
| 1041 | + |
| 1042 | + if ( isset( $row->user_password ) ) { |
| 1043 | + $this->mPassword = $row->user_password; |
| 1044 | + $this->mNewpassword = $row->user_newpassword; |
| 1045 | + $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time ); |
| 1046 | + $this->mEmail = $row->user_email; |
| 1047 | + $this->decodeOptions( $row->user_options ); |
| 1048 | + $this->mTouched = wfTimestamp(TS_MW,$row->user_touched); |
| 1049 | + $this->mToken = $row->user_token; |
| 1050 | + $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated ); |
| 1051 | + $this->mEmailToken = $row->user_email_token; |
| 1052 | + $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires ); |
| 1053 | + $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration ); |
| 1054 | + $this->mEditCount = $row->user_editcount; |
| 1055 | + } else { |
| 1056 | + $all = false; |
| 1057 | + } |
| 1058 | + |
| 1059 | + if ( $all ) { |
| 1060 | + $this->mLoadedItems = true; |
| 1061 | + } |
999 | 1062 | } |
1000 | 1063 | |
1001 | 1064 | /** |
— | — | @@ -1032,7 +1095,7 @@ |
1033 | 1096 | $this->mOptions = null; |
1034 | 1097 | |
1035 | 1098 | if ( $reloadFrom ) { |
1036 | | - $this->mDataLoaded = false; |
| 1099 | + $this->mLoadedItems = array(); |
1037 | 1100 | $this->mFrom = $reloadFrom; |
1038 | 1101 | } |
1039 | 1102 | } |
— | — | @@ -1461,7 +1524,7 @@ |
1462 | 1525 | && User::isIP( $this->mName ) ) { |
1463 | 1526 | // Special case, we know the user is anonymous |
1464 | 1527 | return 0; |
1465 | | - } elseif( $this->mId === null ) { |
| 1528 | + } elseif( !$this->isItemLoaded( 'id' ) ) { |
1466 | 1529 | // Don't load if this was initialized from an ID |
1467 | 1530 | $this->load(); |
1468 | 1531 | } |
— | — | @@ -1482,7 +1545,7 @@ |
1483 | 1546 | * @return String User's name or IP address |
1484 | 1547 | */ |
1485 | 1548 | function getName() { |
1486 | | - if ( !$this->mDataLoaded && $this->mFrom == 'name' ) { |
| 1549 | + if ( $this->isItemLoaded( 'name' ) ) { |
1487 | 1550 | # Special case optimisation |
1488 | 1551 | return $this->mName; |
1489 | 1552 | } else { |
— | — | @@ -1910,7 +1973,10 @@ |
1911 | 1974 | * @return String User's real name |
1912 | 1975 | */ |
1913 | 1976 | function getRealName() { |
1914 | | - $this->load(); |
| 1977 | + if ( !$this->isItemLoaded( 'realname' ) ) { |
| 1978 | + $this->load(); |
| 1979 | + } |
| 1980 | + |
1915 | 1981 | return $this->mRealName; |
1916 | 1982 | } |
1917 | 1983 | |
— | — | @@ -2859,6 +2925,8 @@ |
2860 | 2926 | */ |
2861 | 2927 | function checkTemporaryPassword( $plaintext ) { |
2862 | 2928 | global $wgNewPasswordExpiry; |
| 2929 | + |
| 2930 | + $this->load(); |
2863 | 2931 | if( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) { |
2864 | 2932 | if ( is_null( $this->mNewpassTime ) ) { |
2865 | 2933 | return true; |
— | — | @@ -3174,9 +3242,11 @@ |
3175 | 3243 | * non-existent/anonymous user accounts. |
3176 | 3244 | */ |
3177 | 3245 | public function getRegistration() { |
3178 | | - return $this->getId() > 0 |
3179 | | - ? $this->mRegistration |
3180 | | - : false; |
| 3246 | + if ( $this->isAnon() ) { |
| 3247 | + return false; |
| 3248 | + } |
| 3249 | + $this->load(); |
| 3250 | + return $this->mRegistration; |
3181 | 3251 | } |
3182 | 3252 | |
3183 | 3253 | /** |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -836,11 +836,18 @@ |
837 | 837 | $dbr = wfGetDB( DB_SLAVE ); |
838 | 838 | $userTable = $dbr->tableName( 'user' ); |
839 | 839 | |
| 840 | + if ( $dbr->implicitGroupby() ) { |
| 841 | + $realNameField = 'user_real_name'; |
| 842 | + } else { |
| 843 | + $realNameField = 'FIRST(user_real_name) AS user_real_name'; |
| 844 | + } |
| 845 | + |
840 | 846 | $tables = array( 'revision', 'user' ); |
841 | 847 | |
842 | 848 | $fields = array( |
843 | | - "$userTable.*", |
| 849 | + 'rev_user as user_id', |
844 | 850 | 'rev_user_text AS user_name', |
| 851 | + $realNameField, |
845 | 852 | 'MAX(rev_timestamp) AS timestamp', |
846 | 853 | ); |
847 | 854 | |
Index: trunk/phase3/includes/GlobalFunctions.php |
— | — | @@ -389,9 +389,9 @@ |
390 | 390 | if ( $forward ) { |
391 | 391 | $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; |
392 | 392 | } |
393 | | - // Don't unstub $wgUser at this late stage just for statistics purposes |
| 393 | + // Don't load $wgUser at this late stage just for statistics purposes |
394 | 394 | // FIXME: We can detect some anons even if it is not loaded. See User::getId() |
395 | | - if ( $wgUser->mDataLoaded && $wgUser->isAnon() ) { |
| 395 | + if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) { |
396 | 396 | $forward .= ' anon'; |
397 | 397 | } |
398 | 398 | $log = sprintf( "%s\t%04.3f\t%s\n", |
Index: trunk/phase3/includes/db/Database.php |
— | — | @@ -668,7 +668,7 @@ |
669 | 669 | # Add a comment for easy SHOW PROCESSLIST interpretation |
670 | 670 | # if ( $fname ) { |
671 | 671 | global $wgUser; |
672 | | - if ( is_object( $wgUser ) && $wgUser->mDataLoaded ) { |
| 672 | + if ( is_object( $wgUser ) && $wgUser->isItemLoaded( 'name' ) ) { |
673 | 673 | $userName = $wgUser->getName(); |
674 | 674 | if ( mb_strlen( $userName ) > 15 ) { |
675 | 675 | $userName = mb_substr( $userName, 0, 15 ) . '...'; |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -254,6 +254,7 @@ |
255 | 255 | * (bug 27249) "Installed software" table in Special:Version should always be |
256 | 256 | left-to-right. |
257 | 257 | * (bug 28719) Do not call mLinkHolders __destruct explicitly |
| 258 | +* (bug 21196) Article::getContributors() no longer fail on PostgreSQL. |
258 | 259 | |
259 | 260 | === API changes in 1.18 === |
260 | 261 | * (bug 26339) Throw warning when truncating an overlarge API result. |