Permalink
bc7a1e6 Oct 25, 2014
515 lines (457 sloc) 11.8 KB
<?php
namespace SimpleUser;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* A simple User model.
*
* @package SimpleUser
*/
class User implements AdvancedUserInterface, \Serializable
{
protected $id;
protected $email;
protected $password;
protected $salt;
protected $roles = array();
protected $name = '';
protected $timeCreated;
protected $username;
protected $isEnabled = true;
protected $confirmationToken;
protected $timePasswordResetRequested;
protected $customFields = array();
/**
* Constructor.
*
* @param string $email
*/
public function __construct($email)
{
$this->email = $email;
$this->timeCreated = time();
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
}
/**
* Returns the roles granted to the user. Note that all users have the ROLE_USER role.
*
* @return array A list of the user's roles.
*/
public function getRoles()
{
$roles = $this->roles;
// Every user must have at least one role, per Silex security docs.
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
/**
* Set the user's roles to the given list.
*
* @param array $roles
*/
public function setRoles(array $roles)
{
$this->roles = array();
foreach ($roles as $role) {
$this->addRole($role);
}
}
/**
* Test whether the user has the given role.
*
* @param string $role
* @return bool
*/
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
/**
* Add the given role to the user.
*
* @param string $role
*/
public function addRole($role)
{
$role = strtoupper($role);
if ($role === 'ROLE_USER') {
return;
}
if (!$this->hasRole($role)) {
$this->roles[] = $role;
}
}
/**
* Remove the given role from the user.
*
* @param string $role
*/
public function removeRole($role)
{
if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
unset($this->roles[$key]);
$this->roles = array_values($this->roles);
}
}
/**
* Set the user ID.
*
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get the user ID.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get the encoded password used to authenticate the user.
*
* On authentication, a plain-text password will be salted,
* encoded, and then compared to this value.
*
* @return string The encoded password.
*/
public function getPassword()
{
return $this->password;
}
/**
* Set the encoded password.
*
* @param string $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* Set the salt that should be used to encode the password.
*
* @param string $salt
*/
public function setSalt($salt)
{
$this->salt = $salt;
}
/**
* Returns the salt that was originally used to encode the password.
*
* This can return null if the password was not encoded using a salt.
*
* @return string The salt
*/
public function getSalt()
{
return $this->salt;
}
/**
* Returns the username, if not empty, otherwise the email address.
*
* Email is returned as a fallback because username is optional,
* but the Symfony Security system depends on getUsername() returning a value.
* Use getRealUsername() to get the actual username value.
*
* This method is required by the UserInterface.
*
* @see getRealUsername
* @return string The username, if not empty, otherwise the email.
*/
public function getUsername()
{
return $this->username ?: $this->email;
}
/**
* Get the actual username value that was set,
* or null if no username has been set.
* Compare to getUsername, which returns the email if username is not set.
*
* @see getUsername
* @return string|null
*/
public function getRealUsername()
{
return $this->username;
}
/**
* Test whether username has ever been set (even if it's currently empty).
*
* @return bool
*/
public function hasRealUsername()
{
return !is_null($this->username);
}
/**
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* @return string The user's email address.
*/
public function getEmail()
{
return $this->email;
}
/**
* @param string $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns the name, if set, or else "Anonymous {id}".
*
* @return string
*/
public function getDisplayName()
{
return $this->name ?: 'Anonymous ' . $this->id;
}
/**
* Set the time the user was originally created.
*
* @param int $timeCreated A timestamp value.
*/
public function setTimeCreated($timeCreated)
{
$this->timeCreated = $timeCreated;
}
/**
* Set the time the user was originally created.
*
* @return int
*/
public function getTimeCreated()
{
return $this->timeCreated;
}
/**
* Removes sensitive data from the user.
*
* This is a no-op, since we never store the plain text credentials in this object.
* It's required by UserInterface.
*
* @return void
*/
public function eraseCredentials()
{
}
/**
* The Symfony Security component stores a serialized User object in the session.
* We only need it to store the user ID, because the user provider's refreshUser() method is called on each request
* and reloads the user by its ID.
*
* @see \Serializable::serialize()
*/
public function serialize()
{
return serialize(array(
$this->id,
));
}
/**
* @see \Serializable::unserialize()
*/
public function unserialize($serialized)
{
list (
$this->id,
) = unserialize($serialized);
}
/**
* Validate the user object.
*
* @return array An array of error messages, or an empty array if there were no errors.
*/
public function validate()
{
$errors = array();
if (!$this->getEmail()) {
$errors['email'] = 'Email address is required.';
} else if (!strpos($this->getEmail(), '@')) {
// Basic email format sanity check. Real validation comes from sending them an email with a link they have to click.
$errors['email'] = 'Email address appears to be invalid.';
} else if (strlen($this->getEmail()) > 100) {
$errors['email'] = 'Email address can\'t be longer than 100 characters.';
}
if (!$this->getPassword()) {
$errors['password'] = 'Password is required.';
} else if (strlen($this->getPassword()) > 255) {
$errors['password'] = 'Password can\'t be longer than 255 characters.';
}
if (strlen($this->getName()) > 100) {
$errors['name'] = 'Name can\'t be longer than 100 characters.';
}
// Username can't contain "@",
// because that's how we distinguish between email and username when signing in.
// (It's possible to sign in by providing either one.)
if ($this->getRealUsername() && strpos($this->getRealUsername(), '@') !== false) {
$errors['username'] = 'Username cannot contain the "@" symbol.';
}
return $errors;
}
/**
* @param string $customField
* @return bool
*/
public function hasCustomField($customField)
{
return array_key_exists($customField, $this->customFields);
}
/**
* @param string $customField
* @return mixed|null
*/
public function getCustomField($customField)
{
return $this->hasCustomField($customField) ? $this->customFields[$customField] : null;
}
/**
* @param string $customField
* @param mixed $value
*/
public function setCustomField($customField, $value)
{
$this->customFields[$customField] = $value;
}
/**
* @param array|null $customFields
*/
public function setCustomFields($customFields)
{
$this->customFields = $customFields;
}
/**
* @return array
*/
public function getCustomFields()
{
return $this->customFields;
}
/**
* Checks whether the user's account has expired.
*
* Internally, if this method returns false, the authentication system
* will throw an AccountExpiredException and prevent login.
*
* @return bool true if the user's account is non expired, false otherwise
*
* @see AccountExpiredException
*/
public function isAccountNonExpired()
{
return true;
}
/**
* Checks whether the user is locked.
*
* Internally, if this method returns false, the authentication system
* will throw a LockedException and prevent login.
*
* @return bool true if the user is not locked, false otherwise
*
* @see LockedException
*/
public function isAccountNonLocked()
{
return true;
}
/**
* Checks whether the user's credentials (password) has expired.
*
* Internally, if this method returns false, the authentication system
* will throw a CredentialsExpiredException and prevent login.
*
* @return bool true if the user's credentials are non expired, false otherwise
*
* @see CredentialsExpiredException
*/
public function isCredentialsNonExpired()
{
return true;
}
/**
* Checks whether the user is enabled.
*
* Internally, if this method returns false, the authentication system
* will throw a DisabledException and prevent login.
*
* Users are enabled by default.
*
* @return bool true if the user is enabled, false otherwise
*
* @see DisabledException
*/
public function isEnabled()
{
return $this->isEnabled;
}
/**
* Set whether the user is enabled.
*
* @param bool $isEnabled
*/
public function setEnabled($isEnabled)
{
$this->isEnabled = (bool) $isEnabled;
}
public function setConfirmationToken($token)
{
$this->confirmationToken = $token;
}
public function getConfirmationToken()
{
return $this->confirmationToken;
}
/**
* @param int|null $timestamp
*/
public function setTimePasswordResetRequested($timestamp)
{
$this->timePasswordResetRequested = $timestamp ?: null;
}
/**
* @return int|null
*/
public function getTimePasswordResetRequested()
{
return $this->timePasswordResetRequested;
}
/**
* @param int $ttl Password reset request TTL, in seconds.
* @return bool
*/
public function isPasswordResetRequestExpired($ttl)
{
$timeRequested = $this->getTimePasswordResetRequested();
if (!$timeRequested) {
return true;
}
return $timeRequested + $ttl < time();
}
}