diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index cfbdffb..b010385 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1915,8 +1915,13 @@ function install_configure_form_submit($form, &$form_state) { // We precreated user 1 with placeholder values. Let's save the real values. $account = user_load(1); - $merge_data = array('init' => $form_state['values']['account']['mail'], 'roles' => !empty($account->roles) ? $account->roles : array(), 'status' => 1, 'timezone' => $form_state['values']['date_default_timezone']); - user_save($account, array_merge($form_state['values']['account'], $merge_data)); + $account->init = $account->mail = $form_state['values']['account']['mail']; + $account->roles = !empty($account->roles) ? $account->roles : array(); + $account->status = 1; + $account->timezone = $form_state['values']['date_default_timezone']; + $account->pass = $form_state['values']['account']['pass']; + $account->name = $form_state['values']['account']['name']; + $account->save(); // Load global $user and perform final login tasks. $user = user_load(1); user_login_finalize(); diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 25bd3b1..a541409 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -628,9 +628,9 @@ function block_form_user_profile_form_alter(&$form, &$form_state) { /** * Implements hook_user_presave(). */ -function block_user_presave(&$edit, $account) { - if (isset($edit['block'])) { - $edit['data']['block'] = $edit['block']; +function block_user_presave($account) { + if (isset($account->block)) { + $account->data['block'] = $account->block; } } diff --git a/core/modules/block/block.test b/core/modules/block/block.test index 4af6240..4642da2 100644 --- a/core/modules/block/block.test +++ b/core/modules/block/block.test @@ -542,8 +542,8 @@ class BlockCacheTestCase extends DrupalWebTestCase { $this->normal_user_alt = $this->drupalCreateUser(); // Sync the roles, since drupalCreateUser() creates separate roles for // the same permission sets. - user_save($this->normal_user_alt, array('roles' => $this->normal_user->roles)); $this->normal_user_alt->roles = $this->normal_user->roles; + $this->normal_user_alt->save(); // Enable our test block. $edit['blocks[block_test_test_cache][region]'] = 'sidebar_first'; diff --git a/core/modules/comment/comment.entity.inc b/core/modules/comment/comment.entity.inc index bce8b56..cb4d6d6 100644 --- a/core/modules/comment/comment.entity.inc +++ b/core/modules/comment/comment.entity.inc @@ -73,6 +73,19 @@ class Comment extends Entity { */ public $homepage; + /** + * Implements EntityInterface::id(). + */ + public function id() { + return $this->cid; + } + + /** + * Implements EntityInterface::bundle(). + */ + public function bundle() { + return $this->node_type; + } } /** diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module index 89ce0bc..c695c7e 100644 --- a/core/modules/contact/contact.module +++ b/core/modules/contact/contact.module @@ -233,8 +233,8 @@ function contact_form_user_profile_form_alter(&$form, &$form_state) { /** * Implements hook_user_presave(). */ -function contact_user_presave(&$edit, $account) { - $edit['data']['contact'] = isset($edit['contact']) ? $edit['contact'] : variable_get('contact_default_status', 1); +function contact_user_presave($account) { + $account->data['contact'] = isset($account->contact) ? $account->contact : variable_get('contact_default_status', 1); } /** diff --git a/core/modules/contact/contact.test b/core/modules/contact/contact.test index d7f26ac..490d8f8 100644 --- a/core/modules/contact/contact.test +++ b/core/modules/contact/contact.test @@ -374,7 +374,8 @@ class ContactPersonalTestCase extends DrupalWebTestCase { // Re-create our contacted user as a blocked user. $this->contact_user = $this->drupalCreateUser(); - user_save($this->contact_user, array('status' => 0)); + $this->contact_user->status = 0; + $this->contact_user->save(); // Test that blocked users can still be contacted by admin. $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); diff --git a/core/modules/entity/entity.class.inc b/core/modules/entity/entity.class.inc index 7ffd496..2311af5 100644 --- a/core/modules/entity/entity.class.inc +++ b/core/modules/entity/entity.class.inc @@ -146,27 +146,6 @@ class Entity implements EntityInterface { protected $entityType; /** - * Information about the entity's type. - * - * @var array - */ - protected $entityInfo; - - /** - * The entity ID key. - * - * @var string - */ - protected $idKey; - - /** - * The entity bundle key. - * - * @var string - */ - protected $bundleKey; - - /** * Boolean indicating whether the entity should be forced to be new. * * @var bool @@ -178,7 +157,6 @@ class Entity implements EntityInterface { */ public function __construct(array $values = array(), $entity_type) { $this->entityType = $entity_type; - $this->setUp(); // Set initial values. foreach ($values as $key => $value) { $this->$key = $value; @@ -186,26 +164,17 @@ class Entity implements EntityInterface { } /** - * Sets up the object instance on construction or unserialization. - */ - protected function setUp() { - $this->entityInfo = entity_get_info($this->entityType); - $this->idKey = $this->entityInfo['entity keys']['id']; - $this->bundleKey = isset($this->entityInfo['entity keys']['bundle']) ? $this->entityInfo['entity keys']['bundle'] : NULL; - } - - /** * Implements EntityInterface::id(). */ public function id() { - return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL; + return isset($this->id) ? $this->id : NULL; } /** * Implements EntityInterface::isNew(). */ public function isNew() { - return !empty($this->enforceIsNew) || empty($this->{$this->idKey}); + return !empty($this->enforceIsNew) || !$this->id(); } /** @@ -226,7 +195,7 @@ class Entity implements EntityInterface { * Implements EntityInterface::bundle(). */ public function bundle() { - return isset($this->bundleKey) ? $this->{$this->bundleKey} : $this->entityType; + return $this->entityType; } /** @@ -236,11 +205,12 @@ class Entity implements EntityInterface { */ public function label() { $label = FALSE; - if (isset($this->entityInfo['label callback']) && function_exists($this->entityInfo['label callback'])) { - $label = $this->entityInfo['label callback']($this->entityType, $this); + $entity_info = $this->entityInfo(); + if (isset($entity_info['label callback']) && function_exists($entity_info['label callback'])) { + $label = $entity_info['label callback']($this->entityType, $this); } - elseif (!empty($this->entityInfo['entity keys']['label']) && isset($this->{$this->entityInfo['entity keys']['label']})) { - $label = $this->{$this->entityInfo['entity keys']['label']}; + elseif (!empty($entity_info['entity keys']['label']) && isset($this->{$entity_info['entity keys']['label']})) { + $label = $this->{$entity_info['entity keys']['label']}; } return $label; } @@ -254,11 +224,12 @@ class Entity implements EntityInterface { $bundle = $this->bundle(); // A bundle-specific callback takes precedence over the generic one for the // entity type. - if (isset($this->entityInfo['bundles'][$bundle]['uri callback'])) { - $uri_callback = $this->entityInfo['bundles'][$bundle]['uri callback']; + $entity_info = $this->entityInfo(); + if (isset($entity_info['bundles'][$bundle]['uri callback'])) { + $uri_callback = $entity_info['bundles'][$bundle]['uri callback']; } - elseif (isset($this->entityInfo['uri callback'])) { - $uri_callback = $this->entityInfo['uri callback']; + elseif (isset($entity_info['uri callback'])) { + $uri_callback = $entity_info['uri callback']; } else { return NULL; @@ -304,28 +275,6 @@ class Entity implements EntityInterface { * Implements EntityInterface::entityInfo(). */ public function entityInfo() { - return $this->entityInfo; - } - - /** - * Serializes only what is necessary. - * - * See @link http://www.php.net/manual/language.oop5.magic.php#language.oop5.magic.sleep PHP Magic Methods @endlink. - */ - public function __sleep() { - $vars = get_object_vars($this); - unset($vars['entityInfo'], $vars['idKey'], $vars['bundleKey']); - // Also key the returned array with the variable names so the method may - // be easily overridden and customized. - return drupal_map_assoc(array_keys($vars)); - } - - /** - * Invokes setUp() on unserialization. - * - * See @link http://www.php.net/manual/language.oop5.magic.php#language.oop5.magic.sleep PHP Magic Methods @endlink - */ - public function __wakeup() { - $this->setUp(); + return entity_get_info($this->entityType); } } diff --git a/core/modules/entity/tests/entity_crud_hook_test.test b/core/modules/entity/tests/entity_crud_hook_test.test index be59e99..f582c74 100644 --- a/core/modules/entity/tests/entity_crud_hook_test.test +++ b/core/modules/entity/tests/entity_crud_hook_test.test @@ -356,16 +356,15 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { * Tests hook invocations for CRUD operations on users. */ public function testUserHooks() { - $edit = array( + $account = entity_create('user', array( 'name' => 'Test user', 'mail' => 'test@example.com', 'created' => REQUEST_TIME, 'status' => 1, 'language' => 'en', - ); - $account = (object) $edit; + )); $_SESSION['entity_crud_hook_test'] = array(); - $account = user_save($account, $edit); + $account->save(); $this->assertHookMessageOrder(array( 'entity_crud_hook_test_user_presave called', @@ -375,7 +374,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { )); $_SESSION['entity_crud_hook_test'] = array(); - $account = user_load($account->uid); + user_load($account->uid); $this->assertHookMessageOrder(array( 'entity_crud_hook_test_entity_load called for type user', @@ -383,8 +382,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { )); $_SESSION['entity_crud_hook_test'] = array(); - $edit['name'] = 'New name'; - $account = user_save($account, $edit); + $account->name = 'New name'; + $account->save(); $this->assertHookMessageOrder(array( 'entity_crud_hook_test_user_presave called', diff --git a/core/modules/file/tests/file.test b/core/modules/file/tests/file.test index 05083fc..92b7ef3 100644 --- a/core/modules/file/tests/file.test +++ b/core/modules/file/tests/file.test @@ -709,9 +709,8 @@ class FileFieldRevisionTestCase extends FileFieldTestCase { // Attach the second file to a user. $user = $this->drupalCreateUser(); - $edit = (array) $user; - $edit[$field_name][LANGUAGE_NOT_SPECIFIED][0] = (array) $node_file_r3; - user_save($user, $edit); + $user->{$field_name}[LANGUAGE_NOT_SPECIFIED][0] = (array) $node_file_r3; + $user->save(); $this->drupalGet('user/' . $user->uid . '/edit'); // Delete the third revision and check that the file is not deleted yet. diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module index a3df38f..ddde6db 100644 --- a/core/modules/openid/openid.module +++ b/core/modules/openid/openid.module @@ -83,15 +83,15 @@ function openid_help($path, $arg) { /** * Implements hook_user_insert(). */ -function openid_user_insert(&$edit, $account) { - if (!empty($edit['openid_claimed_id'])) { +function openid_user_insert($account) { + if (!empty($account->openid_claimed_id)) { // The user has registered after trying to log in via OpenID. if (variable_get('user_email_verification', TRUE)) { drupal_set_message(t('Once you have verified your e-mail address, you may log in via OpenID.')); } - user_set_authmaps($account, array('authname_openid' => $edit['openid_claimed_id'])); + user_set_authmaps($account, array('authname_openid' => $account->openid_claimed_id)); unset($_SESSION['openid']); - unset($edit['openid_claimed_id']); + unset($account->openid_claimed_id); } } @@ -100,7 +100,7 @@ function openid_user_insert(&$edit, $account) { * * Save openid_identifier to visitor cookie. */ -function openid_user_login(&$edit, $account) { +function openid_user_login($account) { if (isset($_SESSION['openid'])) { // The user has logged in via OpenID. user_cookie_save(array_intersect_key($_SESSION['openid']['user_login_values'], array_flip(array('openid_identifier')))); diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test index 7a4c9cf..e6a4f46 100644 --- a/core/modules/openid/openid.test +++ b/core/modules/openid/openid.test @@ -189,9 +189,9 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->addIdentity($identity); $response = variable_get('openid_test_hook_openid_response_response'); - $account = variable_get('openid_test_hook_openid_response_account'); + $account_uid = variable_get('openid_test_hook_openid_response_account'); $this->assertEqual($response['openid.claimed_id'], $identity, t('hook_openid_response() was invoked.')); - $this->assertEqual($account->uid, $this->web_user->uid, t('Proper user object passed to hook_openid_response().')); + $this->assertEqual($account_uid, $this->web_user->uid, 'Proper user object passed to hook_openid_response().'); $this->drupalLogout(); @@ -201,9 +201,9 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { $this->submitLoginForm($identity); $this->assertLink(t('Log out'), 0, t('User was logged in.')); $response = variable_get('openid_test_hook_openid_response_response'); - $account = variable_get('openid_test_hook_openid_response_account'); + $account_uid = variable_get('openid_test_hook_openid_response_account'); $this->assertEqual($response['openid.claimed_id'], $identity, t('hook_openid_response() was invoked.')); - $this->assertEqual($account->uid, $this->web_user->uid, t('Proper user object passed to hook_openid_response().')); + $this->assertEqual($account_uid, $this->web_user->uid, 'Proper user object passed to hook_openid_response().'); $this->drupalLogout(); @@ -571,7 +571,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { $user = user_load_by_name('john'); $this->assertTrue($user, t('User was registered with right username.')); - $this->assertFalse($user->preferred_langcode, t('No user language was saved.')); + $this->assertEqual($user->preferred_langcode, LANGUAGE_NOT_SPECIFIED, 'No user language was saved.'); $this->assertFalse($user->data, t('No additional user info was saved.')); // Follow the one-time login that was sent in the welcome e-mail. @@ -611,7 +611,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { $user = user_load_by_name('john'); $this->assertTrue($user, t('User was registered with right username.')); - $this->assertFalse($user->preferred_langcode, t('No user language was saved.')); + $this->assertEqual($user->preferred_langcode, LANGUAGE_NOT_SPECIFIED, 'No user language was saved.'); $this->assertFalse($user->data, t('No additional user info was saved.')); // Follow the one-time login that was sent in the welcome e-mail. diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module index 5bd2f4d..0db8a05 100644 --- a/core/modules/openid/tests/openid_test.module +++ b/core/modules/openid/tests/openid_test.module @@ -378,5 +378,5 @@ function openid_test_openid_request_alter(&$request, $service) { */ function openid_test_openid_response($response, $account) { variable_set('openid_test_hook_openid_response_response', $response); - variable_set('openid_test_hook_openid_response_account', $account ? $account : FALSE); + variable_set('openid_test_hook_openid_response_account', $account ? $account->uid : FALSE); } diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module index 58dcbab..f62cf57 100644 --- a/core/modules/overlay/overlay.module +++ b/core/modules/overlay/overlay.module @@ -102,9 +102,9 @@ function overlay_form_user_profile_form_alter(&$form, &$form_state) { /** * Implements hook_user_presave(). */ -function overlay_user_presave(&$edit, $account) { - if (isset($edit['overlay'])) { - $edit['data']['overlay'] = $edit['overlay']; +function overlay_user_presave($account) { + if (isset($account->overlay)) { + $account->data['overlay'] = $account->overlay; } } @@ -311,7 +311,9 @@ function overlay_user_dismiss_message() { return MENU_ACCESS_DENIED; } else { - user_save(user_load($user->uid), array('data' => array('overlay_message_dismissed' => 1))); + $account = user_load($user->uid); + $account->data['overlay_message_dismissed'] = 1; + $account->save(); drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.')); // Destination is normally given. Go to the user profile as a fallback. drupal_goto('user/' . $user->uid . '/edit'); diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index 7163739..c6f0c92 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1126,7 +1126,8 @@ class DrupalWebTestCase extends DrupalTestCase { $edit['roles'] = array($rid => $rid); } - $account = user_save(drupal_anonymous_user(), $edit); + $account = entity_create('user', $edit); + $account->save(); $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login')); if (empty($account->uid)) { @@ -1230,7 +1231,7 @@ class DrupalWebTestCase extends DrupalTestCase { * * @see drupalCreateUser() */ - protected function drupalLogin(stdClass $user) { + protected function drupalLogin($user) { if ($this->loggedInUser) { $this->drupalLogout(); } diff --git a/core/modules/simpletest/tests/session.test b/core/modules/simpletest/tests/session.test index 6303ca5..bc17bae 100644 --- a/core/modules/simpletest/tests/session.test +++ b/core/modules/simpletest/tests/session.test @@ -41,8 +41,8 @@ class SessionTestCase extends DrupalWebTestCase { // Verify that the session is regenerated if a module calls exit // in hook_user_login(). - user_save($user, array('name' => 'session_test_user')); $user->name = 'session_test_user'; + $user->save(); $this->drupalGet('session-test/id'); $matches = array(); preg_match('/\s*session_id:(.*)\n/', $this->drupalGetContent(), $matches); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 82013ce..ceab02e 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2009,9 +2009,9 @@ function system_form_user_register_form_alter(&$form, &$form_state) { } /** - * Implements hook_user_insert(). + * Implements hook_user_presave(). */ -function system_user_presave(&$edit, $account) { +function system_user_presave($account) { if (variable_get('configurable_timezones', 1) && empty($account->timezone) && !variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT)) { $account->timezone = variable_get('date_default_timezone', ''); } @@ -2021,7 +2021,7 @@ function system_user_presave(&$edit, $account) { /** * Implements hook_user_login(). */ -function system_user_login(&$edit, $account) { +function system_user_login($account) { // If the user has a NULL time zone, notify them to set a time zone. if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) { drupal_set_message(t('Configure your account time zone setting.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone'))))); diff --git a/core/modules/taxonomy/taxonomy.entity.inc b/core/modules/taxonomy/taxonomy.entity.inc index 00182d8..3562580 100644 --- a/core/modules/taxonomy/taxonomy.entity.inc +++ b/core/modules/taxonomy/taxonomy.entity.inc @@ -75,6 +75,20 @@ class TaxonomyTerm extends Entity { * @var string */ public $vocabulary_machine_name; + + /** + * Implements EntityInterface::id(). + */ + public function id() { + return $this->tid; + } + + /** + * Implements EntityInterface::bundle(). + */ + public function bundle() { + return $this->vocabulary_machine_name; + } } /** @@ -263,6 +277,13 @@ class TaxonomyVocabulary extends Entity { * @var integer */ public $weight = 0; + + /** + * Implements EntityInterface::id(). + */ + public function id() { + return $this->vid; + } } /** diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 0bd31ef..719817b 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -1531,8 +1531,8 @@ function taxonomy_rdf_mapping() { function taxonomy_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) { foreach ($items as $delta => $item) { if ($item['tid'] == 'autocreate') { + unset($item['tid']); $term = entity_create('taxonomy_term', $item); - unset($term->tid); $term->langcode = $langcode; taxonomy_term_save($term); $items[$delta]['tid'] = $term->tid; diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test index 00c29dd..65d6805 100644 --- a/core/modules/taxonomy/taxonomy.test +++ b/core/modules/taxonomy/taxonomy.test @@ -400,7 +400,7 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase { // connected to this vocabulary name should have been removed when the // module was uninstalled. Creating a new field with the same name and // an instance of this field on the same bundle name should be successful. - unset($this->vocabulary->vid); + $this->vocabulary->enforceIsNew(); taxonomy_vocabulary_save($this->vocabulary); unset($this->field['id']); field_create_field($this->field); diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/User.php new file mode 100644 index 0000000..46a8362 --- /dev/null +++ b/core/modules/user/lib/Drupal/user/User.php @@ -0,0 +1,145 @@ +uid; + } +} diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php new file mode 100644 index 0000000..3f73832 --- /dev/null +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -0,0 +1,227 @@ + $record) { + if ($record->picture) { + $picture_fids[] = $record->picture; + } + $queried_users[$key]->data = unserialize($record->data); + $queried_users[$key]->roles = array(); + if ($record->uid) { + $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; + } + else { + $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; + } + } + + // Add any additional roles from the database. + $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users))); + foreach ($result as $record) { + $queried_users[$record->uid]->roles[$record->rid] = $record->name; + } + + // Add the full file objects for user pictures if enabled. + if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) { + $pictures = file_load_multiple($picture_fids); + foreach ($queried_users as $entity) { + if (!empty($entity->picture) && isset($pictures[$entity->picture])) { + $entity->picture = $pictures[$entity->picture]; + } + } + } + // Call the default attachLoad() method. This will add fields and call + // hook_user_load(). + parent::attachLoad($queried_users, $revision_id); + } + + /** + * Overrides EntityDatabaseStorageController::create(). + */ + public function create(array $values) { + if (!isset($values['created'])) { + $values['created'] = REQUEST_TIME; + } + // Users always have the authenticated user role. + $values['roles'][DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; + + return parent::create($values); + } + + /** + * Overrides EntityDatabaseStorageController::save(). + */ + public function save(EntityInterface $entity) { + if (empty($entity->uid)) { + $entity->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField()); + $entity->enforceIsNew(); + } + parent::save($entity); + } + + /** + * Overrides EntityDatabaseStorageController::preSave(). + */ + protected function preSave(EntityInterface $entity) { + // Update the user password if it has changed. + if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) { + // Allow alternate password hashing schemes. + require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc'); + $entity->pass = user_hash_password(trim($entity->pass)); + // Abort if the hashing failed and returned FALSE. + if (!$entity->pass) { + throw new EntityMalformedException("The entity doesn't have a password."); + } + } + + if (!empty($entity->picture_upload)) { + $entity->picture = $entity->picture_upload; + } + // Delete the picture if the submission indicates that it should be deleted + // and no replacement was submitted. + elseif (!empty($entity->picture_delete)) { + $entity->picture = 0; + file_usage_delete($entity->original->picture, 'user', 'user', $entity->uid); + file_delete($entity->original->picture); + } + + if (!$entity->isNew()) { + // Process picture uploads. + if (!empty($entity->picture->fid) && (!isset($entity->original->picture->fid) || $entity->picture->fid != $entity->original->picture->fid)) { + $picture = $entity->picture; + // If the picture is a temporary file, move it to its final location + // and make it permanent. + if (!$picture->status) { + $info = image_get_info($picture->uri); + $picture_directory = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures'); + + // Prepare the pictures directory. + file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY); + $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $entity->uid . '-' . REQUEST_TIME . '.' . $info['extension']); + + // Move the temporary file into the final location. + if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) { + $picture->status = FILE_STATUS_PERMANENT; + $entity->picture = file_save($picture); + file_usage_add($picture, 'user', 'user', $entity->uid); + } + } + // Delete the previous picture if it was deleted or replaced. + if (!empty($entity->original->picture->fid)) { + file_usage_delete($entity->original->picture, 'user', 'user', $entity->uid); + file_delete($entity->original->picture); + } + } + $entity->picture = empty($entity->picture->fid) ? 0 : $entity->picture->fid; + + // If the password is empty, that means it was not changed, so use the + // original password. + if (empty($entity->pass)) { + $entity->pass = $entity->original->pass; + } + } + + // Prepare user roles. + if (isset($entity->roles)) { + $entity->roles = array_filter($entity->roles); + } + + // Move account cancellation information into $entity->data. + foreach (array('user_cancel_method', 'user_cancel_notify') as $key) { + if (isset($entity->{$key})) { + $entity->data[$key] = $entity->{$key}; + } + } + } + + /** + * Overrides EntityDatabaseStorageController::postSave(). + */ + protected function postSave(EntityInterface $entity, $update) { + + if ($update) { + // If the password has been changed, delete all open sessions for the + // user and recreate the current one. + if ($entity->pass != $entity->original->pass) { + drupal_session_destroy_uid($entity->uid); + if ($entity->uid == $GLOBALS['user']->uid) { + drupal_session_regenerate(); + } + } + + // Remove roles that are no longer enabled for the user. + $entity->roles = array_filter($entity->roles); + + // Reload user roles if provided. + if ($entity->roles != $entity->original->roles) { + db_delete('users_roles') + ->condition('uid', $entity->uid) + ->execute(); + + $query = db_insert('users_roles')->fields(array('uid', 'rid')); + foreach (array_keys($entity->roles) as $rid) { + if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { + $query->values(array( + 'uid' => $entity->uid, + 'rid' => $rid, + )); + } + } + $query->execute(); + } + + // If the user was blocked, delete the user's sessions to force a logout. + if ($entity->original->status != $entity->status && $entity->status == 0) { + drupal_session_destroy_uid($entity->uid); + } + + // Send emails after we have the new user object. + if ($entity->status != $entity->original->status) { + // The user's status is changing; conditionally send notification email. + $op = $entity->status == 1 ? 'status_activated' : 'status_blocked'; + _user_mail_notify($op, $entity); + } + } + else { + // Save user roles. + if (count($entity->roles) > 1) { + $query = db_insert('users_roles')->fields(array('uid', 'rid')); + foreach (array_keys($entity->roles) as $rid) { + if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { + $query->values(array( + 'uid' => $entity->uid, + 'rid' => $rid, + )); + } + } + $query->execute(); + } + } + } +} diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index dc16906..574ce32 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -227,67 +227,57 @@ function hook_user_operations() { } /** - * A user account is about to be created or updated. + * Act on a user account being inserted or updated. * - * This hook is primarily intended for modules that want to store properties in - * the serialized {users}.data column, which is automatically loaded whenever a - * user account object is loaded, modules may add to $edit['data'] in order - * to have their data serialized on save. + * This hook is invoked before the user account is saved to the database. + * + * Modules that want to store properties in the serialized {users}.data column, + * which is automatically loaded whenever a user account object is loaded, may + * add their properties to $account->data in order to have their data serialized + * on save. * - * @param $edit - * The array of form values submitted by the user. * @param $account - * The user object on which the operation is performed. + * The user account object. * * @see hook_user_insert() * @see hook_user_update() */ -function hook_user_presave(&$edit, $account) { +function hook_user_presave($account) { // Make sure that our form value 'mymodule_foo' is stored as // 'mymodule_bar' in the 'data' (serialized) column. - if (isset($edit['mymodule_foo'])) { - $edit['data']['mymodule_bar'] = $edit['mymodule_foo']; + if (isset($account->mymodule_foo)) { + $account->data['mymodule_bar'] = $account->mymodule_foo; } } /** - * A user account was created. - * - * The module should save its custom additions to the user object into the - * database. + * Respond to creation of a new user account. * - * @param $edit - * The array of form values submitted by the user. * @param $account - * The user object on which the operation is being performed. + * The user account object. * * @see hook_user_presave() * @see hook_user_update() */ -function hook_user_insert(&$edit, $account) { - db_insert('mytable') +function hook_user_insert($account) { + db_insert('user_changes') ->fields(array( - 'myfield' => $edit['myfield'], 'uid' => $account->uid, + 'created' => time(), )) ->execute(); } /** - * A user account was updated. - * - * Modules may use this hook to update their user data in a custom storage - * after a user account has been updated. + * Respond to updates to a user account. * - * @param $edit - * The array of form values submitted by the user. * @param $account - * The user object on which the operation is performed. + * The user account object. * * @see hook_user_presave() * @see hook_user_insert() */ -function hook_user_update(&$edit, $account) { +function hook_user_update($account) { db_insert('user_changes') ->fields(array( 'uid' => $account->uid, @@ -297,14 +287,12 @@ function hook_user_update(&$edit, $account) { } /** - * The user just logged in. + * Respond to a user logging in. * - * @param $edit - * The array of form values submitted by the user. * @param $account - * The user object on which the operation was just performed. + * The user account object. */ -function hook_user_login(&$edit, $account) { +function hook_user_login($account) { // If the user has a NULL time zone, notify them to set a time zone. if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) { drupal_set_message(t('Configure your account time zone setting.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone'))))); diff --git a/core/modules/user/user.entity.inc b/core/modules/user/user.entity.inc deleted file mode 100644 index 5549c77..0000000 --- a/core/modules/user/user.entity.inc +++ /dev/null @@ -1,52 +0,0 @@ - $record) { - $picture_fids[] = $record->picture; - $queried_users[$key]->data = unserialize($record->data); - $queried_users[$key]->roles = array(); - if ($record->uid) { - $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - } - else { - $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; - } - } - - // Add any additional roles from the database. - $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users))); - foreach ($result as $record) { - $queried_users[$record->uid]->roles[$record->rid] = $record->name; - } - - // Add the full file objects for user pictures if enabled. - if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) { - $pictures = file_load_multiple($picture_fids); - foreach ($queried_users as $account) { - if (!empty($account->picture) && isset($pictures[$account->picture])) { - $account->picture = $pictures[$account->picture]; - } - else { - $account->picture = NULL; - } - } - } - // Call the default attachLoad() method. This will add fields and call - // hook_user_load(). - parent::attachLoad($queried_users, $revision_id); - } -} diff --git a/core/modules/user/user.info b/core/modules/user/user.info index d887352..8dad5a3 100644 --- a/core/modules/user/user.info +++ b/core/modules/user/user.info @@ -3,7 +3,6 @@ description = Manages the user registration and login system. package = Core version = VERSION core = 8.x -files[] = user.entity.inc files[] = user.test required = TRUE configure = admin/config/people diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 865f17b..f320dfb 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -77,33 +77,6 @@ function user_help($path, $arg) { } /** - * Invokes a user hook in every module. - * - * We cannot use module_invoke() for this, because the arguments need to - * be passed by reference. - * - * @param $type - * A text string that controls which user hook to invoke. Valid choices are: - * - cancel: Invokes hook_user_cancel(). - * - insert: Invokes hook_user_insert(). - * - login: Invokes hook_user_login(). - * - presave: Invokes hook_user_presave(). - * - update: Invokes hook_user_update(). - * @param $edit - * An associative array variable containing form values to be passed - * as the first parameter of the hook function. - * @param $account - * The user account object to be passed as the second parameter of the hook - * function. - */ -function user_module_invoke($type, &$edit, $account) { - foreach (module_implements('user_' . $type) as $module) { - $function = $module . '_user_' . $type; - $function($edit, $account); - } -} - -/** * Implements hook_theme(). */ function user_theme() { @@ -145,14 +118,15 @@ function user_theme() { * Implements hook_entity_info(). */ function user_entity_info() { - $return = array( + return array( 'user' => array( 'label' => t('User'), - 'controller class' => 'UserController', + 'controller class' => 'Drupal\user\UserStorageController', 'base table' => 'users', 'uri callback' => 'user_uri', 'label callback' => 'user_label', 'fieldable' => TRUE, + 'entity class' => 'Drupal\user\User', 'entity keys' => array( 'id' => 'uid', ), @@ -173,7 +147,6 @@ function user_entity_info() { ), ), ); - return $return; } /** @@ -360,224 +333,6 @@ function user_load_by_name($name) { } /** - * Save changes to a user account or add a new user. - * - * @param $account - * (optional) The user object to modify or add. If you want to modify - * an existing user account, you will need to ensure that (a) $account - * is an object, and (b) you have set $account->uid to the numeric - * user ID of the user account you wish to modify. If you - * want to create a new user account, you can set $account->is_new to - * TRUE or omit the $account->uid field. - * @param $edit - * An array of fields and values to save. For example array('name' - * => 'My name'). Key / value pairs added to the $edit['data'] will be - * serialized and saved in the {users.data} column. - * - * @return - * A fully-loaded $user object upon successful save or FALSE if the save failed. - * - * @todo D8: Drop $edit and fix user_save() to be consistent with others. - */ -function user_save($account, $edit = array()) { - $transaction = db_transaction(); - try { - if (!empty($edit['pass'])) { - // Allow alternate password hashing schemes. - require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc'); - $edit['pass'] = user_hash_password(trim($edit['pass'])); - // Abort if the hashing failed and returned FALSE. - if (!$edit['pass']) { - return FALSE; - } - } - else { - // Avoid overwriting an existing password with a blank password. - unset($edit['pass']); - } - - // Load the stored entity, if any. - if (!empty($account->uid) && !isset($account->original)) { - $account->original = entity_load_unchanged('user', $account->uid); - } - - if (empty($account)) { - $account = new stdClass(); - } - if (!isset($account->is_new)) { - $account->is_new = empty($account->uid); - } - // Prepopulate $edit['data'] with the current value of $account->data. - // Modules can add to or remove from this array in hook_user_presave(). - if (!empty($account->data)) { - $edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data; - } - - // Invoke hook_user_presave() for all modules. - user_module_invoke('presave', $edit, $account); - - // Invoke presave operations of Field Attach API and Entity API. Those APIs - // require a fully-fledged and updated entity object. Therefore, we need to - // copy any new property values of $edit into it. - foreach ($edit as $key => $value) { - $account->$key = $value; - } - // Default the user entity language to the user's preferred language. - if (!isset($account->langcode) && isset($account->preferred_langcode)) { - $account->langcode = $account->preferred_langcode; - } - field_attach_presave('user', $account); - module_invoke_all('entity_presave', $account, 'user'); - - if (is_object($account) && !$account->is_new) { - // Process picture uploads. - if (!empty($account->picture->fid) && (!isset($account->original->picture->fid) || $account->picture->fid != $account->original->picture->fid)) { - $picture = $account->picture; - // If the picture is a temporary file move it to its final location and - // make it permanent. - if (!$picture->status) { - $info = image_get_info($picture->uri); - $picture_directory = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures'); - - // Prepare the pictures directory. - file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY); - $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '-' . REQUEST_TIME . '.' . $info['extension']); - - // Move the temporary file into the final location. - if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) { - $picture->status = FILE_STATUS_PERMANENT; - $account->picture = file_save($picture); - file_usage_add($picture, 'user', 'user', $account->uid); - } - } - // Delete the previous picture if it was deleted or replaced. - if (!empty($account->original->picture->fid)) { - file_usage_delete($account->original->picture, 'user', 'user', $account->uid); - file_delete($account->original->picture); - } - } - elseif (isset($edit['picture_delete']) && $edit['picture_delete']) { - file_usage_delete($account->original->picture, 'user', 'user', $account->uid); - file_delete($account->original->picture); - } - $account->picture = empty($account->picture->fid) ? 0 : $account->picture->fid; - - // Do not allow 'uid' to be changed. - $account->uid = $account->original->uid; - // Save changes to the user table. - $success = drupal_write_record('users', $account, 'uid'); - if ($success === FALSE) { - // The query failed - better to abort the save than risk further - // data loss. - return FALSE; - } - - // Reload user roles if provided. - if ($account->roles != $account->original->roles) { - db_delete('users_roles') - ->condition('uid', $account->uid) - ->execute(); - - $query = db_insert('users_roles')->fields(array('uid', 'rid')); - foreach (array_keys($account->roles) as $rid) { - if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { - $query->values(array( - 'uid' => $account->uid, - 'rid' => $rid, - )); - } - } - $query->execute(); - } - - // Delete a blocked user's sessions to kick them if they are online. - if ($account->original->status != $account->status && $account->status == 0) { - drupal_session_destroy_uid($account->uid); - } - - // If the password changed, delete all open sessions and recreate - // the current one. - if ($account->pass != $account->original->pass) { - drupal_session_destroy_uid($account->uid); - if ($account->uid == $GLOBALS['user']->uid) { - drupal_session_regenerate(); - } - } - - // Save Field data. - field_attach_update('user', $account); - - // Send emails after we have the new user object. - if ($account->status != $account->original->status) { - // The user's status is changing; conditionally send notification email. - $op = $account->status == 1 ? 'status_activated' : 'status_blocked'; - _user_mail_notify($op, $account); - } - - // Update $edit with any interim changes to $account. - foreach ($account as $key => $value) { - if (!property_exists($account->original, $key) || $value !== $account->original->$key) { - $edit[$key] = $value; - } - } - user_module_invoke('update', $edit, $account); - module_invoke_all('entity_update', $account, 'user'); - } - else { - // Allow 'uid' to be set by the caller. There is no danger of writing an - // existing user as drupal_write_record will do an INSERT. - if (empty($account->uid)) { - $account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField()); - } - // Allow 'created' to be set by the caller. - if (!isset($account->created)) { - $account->created = REQUEST_TIME; - } - $success = drupal_write_record('users', $account); - if ($success === FALSE) { - // On a failed INSERT some other existing user's uid may be returned. - // We must abort to avoid overwriting their account. - return FALSE; - } - - // Make sure $account is properly initialized. - $account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - - field_attach_insert('user', $account); - $edit = (array) $account; - user_module_invoke('insert', $edit, $account); - module_invoke_all('entity_insert', $account, 'user'); - - // Save user roles. - if (count($account->roles) > 1) { - $query = db_insert('users_roles')->fields(array('uid', 'rid')); - foreach (array_keys($account->roles) as $rid) { - if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { - $query->values(array( - 'uid' => $account->uid, - 'rid' => $rid, - )); - } - } - $query->execute(); - } - } - // Clear internal properties. - unset($account->is_new); - unset($account->original); - // Clear the static loading cache. - entity_get_controller('user')->resetCache(array($account->uid)); - - return $account; - } - catch (Exception $e) { - $transaction->rollback(); - watchdog_exception('user', $e); - throw $e; - } -} - -/** * Verify the syntax of the given name. */ function user_validate_name($name) { @@ -1126,14 +881,28 @@ function user_account_form_validate($form, &$form_state) { if ($error = user_validate_name($form_state['values']['name'])) { form_set_error('name', $error); } - elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('name', db_like($form_state['values']['name']), 'LIKE')->range(0, 1)->execute()->fetchField()) { + // Cast the user ID as an integer. It might have been set to NULL, which + // could lead to unexpected results. + elseif ((bool) db_select('users') + ->fields('users', array('uid')) + ->condition('uid', (int) $account->uid, '<>') + ->condition('name', db_like($form_state['values']['name']), 'LIKE') + ->range(0, 1) + ->execute() + ->fetchField()) { form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name']))); } } $mail = $form_state['values']['mail']; - if ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($mail), 'LIKE')->range(0, 1)->execute()->fetchField()) { + if ((bool) db_select('users') + ->fields('users', array('uid')) + ->condition('uid', (int) $account->uid, '<>') + ->condition('mail', db_like($mail), 'LIKE') + ->range(0, 1) + ->execute() + ->fetchField()) { // Format error message dependent on whether the user is logged in or not. if ($GLOBALS['user']->uid) { form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $mail))); @@ -1158,30 +927,6 @@ function user_account_form_validate($form, &$form_state) { } } -/** - * Implements hook_user_presave(). - */ -function user_user_presave(&$edit, $account) { - if (!empty($edit['picture_upload'])) { - $edit['picture'] = $edit['picture_upload']; - } - // Delete picture if requested, and if no replacement picture was given. - elseif (!empty($edit['picture_delete'])) { - $edit['picture'] = NULL; - } - // Prepare user roles. - if (isset($edit['roles'])) { - $edit['roles'] = array_filter($edit['roles']); - } - - // Move account cancellation information into $user->data. - foreach (array('user_cancel_method', 'user_cancel_notify') as $key) { - if (isset($edit[$key])) { - $edit['data'][$key] = $edit[$key]; - } - } -} - function user_login_block($form) { $form['#action'] = url($_GET['q'], array('query' => drupal_get_destination())); $form['#id'] = 'user-login-form'; @@ -2181,7 +1926,8 @@ function user_authenticate($name, $password) { // Update user to new password scheme if needed. if (user_needs_new_hash($account)) { - user_save($account, array('pass' => $password)); + $account->pass = $password; + $account->save(); } } } @@ -2211,7 +1957,7 @@ function user_login_finalize(&$edit = array()) { // or incorrectly does a redirect which would leave the old session in place. drupal_session_regenerate(); - user_module_invoke('login', $edit, $user); + module_invoke_all('user_login', $user); } /** @@ -2236,16 +1982,16 @@ function user_external_login_register($name, $module) { $account = user_external_load($name); if (!$account) { // Register this new user. - $userinfo = array( + $account = entity_create('user', array( 'name' => $name, 'pass' => user_password(), 'init' => $name, 'status' => 1, 'access' => REQUEST_TIME - ); - $account = user_save(drupal_anonymous_user(), $userinfo); - // Terminate if an error occurred during user_save(). - if (!$account) { + )); + $status = $account->save(); + // Terminate if an error occurred while saving the account. + if ($status != SAVED_NEW) { drupal_set_message(t("Error saving user account."), 'error'); return; } @@ -2393,7 +2139,8 @@ function _user_cancel($edit, $account, $method) { if (!empty($edit['user_cancel_notify'])) { _user_mail_notify('status_blocked', $account); } - user_save($account, array('status' => 0)); + $account->status = 0; + $account->save(); drupal_set_message(t('%name has been disabled.', array('%name' => $account->name))); watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE); break; @@ -3147,7 +2894,8 @@ function user_user_operations_unblock($accounts) { foreach ($accounts as $account) { // Skip unblocking user if they are already unblocked. if ($account !== FALSE && $account->status == 0) { - user_save($account, array('status' => 1)); + $account->status = 1; + $account->save(); } } } @@ -3163,7 +2911,8 @@ function user_user_operations_block($accounts) { // For efficiency manually save the original account before applying any // changes. $account->original = clone $account; - user_save($account, array('status' => 0)); + $account->status = 0; + $account->save(); } } } @@ -3172,8 +2921,6 @@ function user_user_operations_block($accounts) { * Callback function for admin mass adding/deleting a user role. */ function user_multiple_role_edit($accounts, $operation, $rid) { - // The role name is not necessary as user_save() will reload the user - // object, but some modules' hook_user() may look at this first. $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField(); switch ($operation) { @@ -3186,7 +2933,8 @@ function user_multiple_role_edit($accounts, $operation, $rid) { // For efficiency manually save the original account before applying // any changes. $account->original = clone $account; - user_save($account, array('roles' => $roles)); + $account->roles = $roles; + $account->save(); } } break; @@ -3199,7 +2947,8 @@ function user_multiple_role_edit($accounts, $operation, $rid) { // For efficiency manually save the original account before applying // any changes. $account->original = clone $account; - user_save($account, array('roles' => $roles)); + $account->roles = $roles; + $account->save(); } } break; @@ -3289,7 +3038,7 @@ function user_multiple_cancel_confirm_submit($form, &$form_state) { if ($uid == $user->uid) { $admin_form_state = $form_state; unset($admin_form_state['values']['user_cancel_confirm']); - $admin_form_state['values']['_account'] = $user; + $admin_form_state['values']['_account'] = user_load($user->uid); user_cancel_confirm_form_submit(array(), $admin_form_state); } else { @@ -3363,7 +3112,7 @@ function user_build_filter_query(SelectInterface $query) { // the authenticated role. If so, then all users would be listed, and we can // skip adding it to the filter query. if ($key == 'permission') { - $account = new stdClass(); + $account = entity_create('user', array()); $account->uid = 'user_filter'; $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1); if (user_access($value, $account)) { @@ -3609,7 +3358,8 @@ function user_block_user_action(&$entity, $context = array()) { $uid = $GLOBALS['user']->uid; } $account = user_load($uid); - $account = user_save($account, array('status' => 0)); + $account->status = 0; + $account->save(); watchdog('action', 'Blocked user %name.', array('%name' => $account->name)); } @@ -3688,7 +3438,7 @@ function user_register_form($form, &$form_state) { drupal_goto('user/' . $user->uid); } - $form['#user'] = drupal_anonymous_user(); + $form['#user'] = entity_create('user', array()); $form['#attached']['library'][] = array('system', 'jquery.cookie'); $form['#attributes']['class'][] = 'user-info-from-cookie'; @@ -3759,14 +3509,10 @@ function user_register_submit($form, &$form_state) { $account = $form['#user']; entity_form_submit_build_entity('user', $account, $form, $form_state); + $status = $account->save(); - // Populate $edit with the properties of $account, which have been edited on - // this form by taking over all values, which appear in the form values too. - $edit = array_intersect_key((array) $account, $form_state['values']); - $account = user_save($account, $edit); - - // Terminate if an error occurred during user_save(). - if (!$account) { + // Terminate if an error occurred while saving the account. + if ($status =! SAVED_NEW) { drupal_set_message(t("Error saving user account."), 'error'); $form_state['redirect'] = ''; return; diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc index f24849c..438fedb 100644 --- a/core/modules/user/user.pages.inc +++ b/core/modules/user/user.pages.inc @@ -264,19 +264,8 @@ function user_profile_form_submit($form, &$form_state) { // Remove unneeded values. form_state_values_clean($form_state); - // Before updating the account entity, keep an unchanged copy for use with - // user_save() later. This is necessary for modules implementing the user - // hooks to be able to react on changes by comparing the values of $account - // and $edit. - $account_unchanged = clone $account; - entity_form_submit_build_entity('user', $account, $form, $form_state); - - // Populate $edit with the properties of $account, which have been edited on - // this form by taking over all values, which appear in the form values too. - $edit = array_intersect_key((array) $account, $form_state['values']); - - user_save($account_unchanged, $edit); + $account->save(); $form_state['values']['uid'] = $account->uid; if (!empty($edit['pass'])) { @@ -400,11 +389,9 @@ function user_cancel_confirm_form_submit($form, &$form_state) { else { // Store cancelling method and whether to notify the user in $account for // user_cancel_confirm(). - $edit = array( - 'user_cancel_method' => $form_state['values']['user_cancel_method'], - 'user_cancel_notify' => $form_state['values']['user_cancel_notify'], - ); - $account = user_save($account, $edit); + $account->user_cancel_method = $form_state['values']['user_cancel_method']; + $account->user_cancel_notify = $form_state['values']['user_cancel_notify']; + $account->save(); _user_mail_notify('cancel_confirm', $account); drupal_set_message(t('A confirmation request to cancel your account has been sent to your e-mail address.')); watchdog('user', 'Sent account cancellation request to %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE); diff --git a/core/modules/user/user.test b/core/modules/user/user.test index 06fbc95..d758e3a 100644 --- a/core/modules/user/user.test +++ b/core/modules/user/user.test @@ -166,9 +166,9 @@ class UserRegistrationTestCase extends DrupalWebTestCase { $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), t('Correct creation time.')); $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, t('Correct status field.')); $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), t('Correct time zone field.')); - $this->assertEqual($new_user->langcode, '', t('Correct language field.')); - $this->assertEqual($new_user->preferred_langcode, '', t('Correct preferred language field.')); - $this->assertEqual($new_user->picture, '', t('Correct picture field.')); + $this->assertEqual($new_user->langcode, LANGUAGE_NOT_SPECIFIED, 'Correct language field.'); + $this->assertEqual($new_user->preferred_langcode, LANGUAGE_NOT_SPECIFIED, 'Correct preferred language field.'); + $this->assertEqual($new_user->picture, 0, t('Correct picture field.')); $this->assertEqual($new_user->init, $mail, t('Correct init field.')); } @@ -553,7 +553,8 @@ class UserCancelTestCase extends DrupalWebTestCase { 'name' => 'user1', 'pass' => user_hash_password(trim($password)), ); - // We cannot use user_save() here or the password would be hashed again. + // We cannot use $account->save() here, because this would result in the + // password being hashed again. db_update('users') ->fields($account) ->condition('uid', 1) @@ -1146,7 +1147,7 @@ class UserPictureTestCase extends DrupalWebTestCase { // Load actual user data from database. $account = user_load($this->user->uid, TRUE); - $pic_path = isset($account->picture) ? $account->picture->uri : NULL; + $pic_path = !empty($account->picture) ? $account->picture->uri : NULL; // Check if image is displayed in user's profile page. $this->drupalGet('user'); @@ -1160,7 +1161,7 @@ class UserPictureTestCase extends DrupalWebTestCase { // Load actual user data from database. $account1 = user_load($this->user->uid, TRUE); - $this->assertNull($account1->picture, 'User object has no picture'); + $this->assertFalse($account1->picture, 'User object has no picture'); $file = file_load($account->picture->fid); $this->assertFalse($file, 'File is removed from database'); @@ -1176,7 +1177,7 @@ class UserPictureTestCase extends DrupalWebTestCase { // Load actual user data from database. $account = user_load($this->user->uid, TRUE); - return isset($account->picture) ? $account->picture->uri : NULL; + return !empty($account->picture) ? $account->picture->uri : NULL; } } @@ -1624,14 +1625,14 @@ class UserBlocksUnitTests extends DrupalWebTestCase { } /** - * Test case to test user_save() behaviour. + * Tests saving a user account. */ class UserSaveTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User save test', - 'description' => 'Test user_save() for arbitrary new uid.', + 'description' => 'Test account saving for arbitrary new uid.', 'group' => 'User', ); } @@ -1646,16 +1647,15 @@ class UserSaveTestCase extends DrupalWebTestCase { $test_name = $this->randomName(); // Create the base user, based on drupalCreateUser(). - $user = array( + $user = entity_create('user', array( 'name' => $test_name, 'uid' => $test_uid, 'mail' => $test_name . '@example.com', - 'is_new' => TRUE, 'pass' => user_password(), 'status' => 1, - ); - $user_by_return = user_save(drupal_anonymous_user(), $user); - $this->assertTrue($user_by_return, t('Loading user by return of user_save().')); + )); + $user->enforceIsNew(); + $user->save(); // Test if created user exists. $user_by_uid = user_load($test_uid); @@ -1713,7 +1713,7 @@ class UserCreateTestCase extends DrupalWebTestCase { } /** - * Test case to test user_save() behaviour. + * Tests editing a user account. */ class UserEditTestCase extends DrupalWebTestCase {