Commit 93c20fd0 authored by catch's avatar catch

Issue #1361228 by marcingy, Niklas Fiekas, fago, cosmicdreams, aspilicious et...

Issue #1361228 by marcingy, Niklas Fiekas, fago, cosmicdreams, aspilicious et al: Make the user entity a classed object.
parent 0594b014
......@@ -1892,8 +1892,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();
......
......@@ -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;
}
}
......
......@@ -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';
......
......@@ -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);
}
/**
......
......@@ -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');
......
......@@ -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',
......
......@@ -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.
......
......@@ -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);
}
}
......
......@@ -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');
......
......@@ -1126,7 +1126,8 @@ protected function drupalCreateUser(array $permissions = array()) {
$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 @@ protected function checkPermissions(array $permissions, $reset = FALSE) {
*
* @see drupalCreateUser()
*/
protected function drupalLogin(stdClass $user) {
protected function drupalLogin($user) {
if ($this->loggedInUser) {
$this->drupalLogout();
}
......
......@@ -2021,15 +2021,14 @@ 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', '');
}
}
/**
* Implements hook_user_login().
*/
......
......@@ -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);
......
<?php
/**
* @file
* Definition of Drupal\user\User.
*/
namespace Drupal\user;
/**
* @todo Switch to PSR-0 for the Entity classes: http://drupal.org/node/1495024
*/
use Entity;
/**
* Defines the user entity class.
*/
class User extends Entity {
/**
* The user ID.
*
* @var integer
*/
public $uid;
/**
* The unique user name.
*
* @var string
*/
public $name = '';
/**
* The user's password (hashed).
*
* @var string
*/
public $pass;
/**
* The user's email address.
*
* @var string
*/
public $mail = '';
/**
* The user's default theme.
*
* @var string
*/
public $theme;
/**
* The user's signature.
*
* @var string
*/
public $signature;
/**
* The user's signature format.
*
* @var string
*/
public $signature_format;
/**
* The timestamp when the user was created.
*
* @var integer
*/
public $created;
/**
* The timestamp when the user last accessed the site. A value of 0 means the
* user has never accessed the site.
*
* @var integer
*/
public $access = 0;
/**
* The timestamp when the user last logged in. A value of 0 means the user has
* never logged in.
*
* @var integer
*/
public $login = 0;
/**
* Whether the user is active (1) or blocked (0).
*
* @var integer
*/
public $status = 0;
/**
* The user's timezone.
*
* @var string
*/
public $timezone;
/**
* The user's langcode.
*
* @var string
*/
public $langcode = LANGUAGE_NOT_SPECIFIED;
/**
* The user's preferred langcode for receiving emails and viewing the site.
*
* @var string
*/
public $preferred_langcode = LANGUAGE_NOT_SPECIFIED;
/**
* The file ID of the user's picture.
*
* @var integer
*/
public $picture = 0;
/**
* The email address used for initial account creation.
*
* @var string
*/
public $init = '';
/**
* The user's roles.
*
* @var array
*/
public $roles = array();
/**
* Implements EntityInterface::id().
*/
public function id() {
return $this->uid;
}
}
<?php
/**
* @file
* Definition of Drupal\user\UserStorageController.
*/
namespace Drupal\user;
/**
* @todo Switch to PSR-0 for the Entity classes: http://drupal.org/node/1495024
*/
use EntityDatabaseStorageController;
use EntityInterface;
/**
* Controller class for users.
*
* This extends the EntityDatabaseStorageController class, adding required
* special handling for user objects.
*/
class UserStorageController extends EntityDatabaseStorageController {
/**
* Overrides EntityDatabaseStorageController::attachLoad().
*/
function attachLoad(&$queried_users, $revision_id = FALSE) {
// Build an array of user picture IDs so that these can be fetched later.
$picture_fids = array();
foreach ($queried_users as $key => $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 does not 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();
}
}
}
}
......@@ -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.
* Respond to creation of a new user account.
*
* The module should save its custom additions to the user object into the
* database.
*
* @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,
......
<?php
/**
* @file Controller class for users.
*/
/**
* Controller class for users.
*
* This extends the DrupalDefaultEntityController class, adding required
* special handling for user objects.
*/
class UserController extends DrupalDefaultEntityController {
function attachLoad(&$queried_users, $revision_id = FALSE) {
// Build an array of user picture IDs so that these can be fetched later.
$picture_fids = array();
foreach ($queried_users as $key => $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;
}