From ff355e87e2f7a41a87c37f43232a44113cb033e0 Mon Sep 17 00:00:00 2001 From: Antoine Musso Date: Wed, 22 May 2013 16:39:31 +0200 Subject: [PATCH] User::saveOptions() optimization Since we only want to save non default user options, we have to strip out any user option that match the default ones. We did that by calling User::getDefaultOption( 'some option name' ); on each of the option. Since the User mOptions property is a merge of the default option, we end up doing a lot of unneeded processing. The loop roughly looks like: User::getDefaultOption() User::getDefaultOptions() Language->getCode() SearchEngine::searchableNamespaces() language->getNamespaces() wfRunHooks('SearcheableNamespaces') wfRunHooks('UserGetDefaultOptions') For EACH of the mOptions. Instead this patch does an array_diff to strip out from mObjects any default option. We still skip options whose value is false or null. Test provided to make sure we only save what we want. Change-Id: Ie98d3a17edab74401ed32f759ba11f723b56e376 --- includes/User.php | 22 +++++++------- tests/phpunit/includes/UserTest.php | 45 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/includes/User.php b/includes/User.php index ca3f79b5de..7f7a22db9d 100644 --- a/includes/User.php +++ b/includes/User.php @@ -4629,20 +4629,20 @@ class User { return; } + $defaultOptions = self::getDefaultOptions(); + $userId = $this->getId(); $insert_rows = array(); - foreach ( $saveOptions as $key => $value ) { - // Don't bother storing default values - $defaultOption = self::getDefaultOption( $key ); - if ( ( is_null( $defaultOption ) && - !( $value === false || is_null( $value ) ) ) || - $value != $defaultOption ) { - $insert_rows[] = array( - 'up_user' => $userId, - 'up_property' => $key, - 'up_value' => $value, - ); + $changedOptions = array_diff_assoc( $saveOptions, $defaultOptions ); + foreach ( $changedOptions as $key => $value ) { + if ( $value === false || is_null( $value ) ) { + continue; } + $insert_rows[] = array( + 'up_user' => $userId, + 'up_property' => $key, + 'up_value' => $value, + ); } $dbw = wfGetDB( DB_MASTER ); diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php index ff33e825ee..b7df3f617d 100644 --- a/tests/phpunit/includes/UserTest.php +++ b/tests/phpunit/includes/UserTest.php @@ -234,4 +234,49 @@ class UserTest extends MediaWikiTestCase { $this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) ); $this->assertEquals( 'test', $this->user->getOption( 'someoption' ) ); } + + /** + * Helper, fetch user properties from the database. + * @param int $userId + */ + function dbUserProperties( $userId ) { + $res = wfGetDB( DB_SLAVE )->select( + 'user_properties', + array( 'up_property', 'up_value' ), + array( 'up_user' => $userId ), + __METHOD__ + ); + $ret = array(); + foreach( $res as $row ) { + $ret[$row->up_property] = $row->up_value; + } + return $ret; + } + + public function testOnlySaveChangedOptions() { + $user = User::newFromName( 'UnitTestUser2' ); + $user->addToDatabase(); + + // Fresh user only has default, so nothing should be in the DB + $dbProps = $this->dbUserProperties( $user->getId() ); + $this->assertEmpty( $dbProps, + "A new user should not have any user property saved in the DB" ); + + // Make sure we only save the altered option + $user->setOption( 'changed_opt', 'alix_20281' ); + $user->setOption( 'switch', 1 ); + $user->setOption( 'anotherswitch', 1 ); + $user->saveSettings(); + + $expected = array ( + 'changed_opt' => 'alix_20281', + 'switch' => '1', + 'anotherswitch' => '1', + ); + $dbProps = $this->dbUserProperties( $user->getId() ); + + $this->assertEquals( $expected, $dbProps, + "non default options should be saved, and default ones should not" ); + + } } -- 2.20.1