Commit 3e347d0e by Alexander Makarov

Merge pull request #2244 from yiisoft/advanced-application-forms

Moved most of the user-related logic into form models
parents 0cde160c a1497ca0
<?php
namespace backend\controllers;
use Yii;
use yii\web\AccessControl;
use yii\web\Controller;
use common\models\LoginForm;
/**
* Site controller
*/
class SiteController extends Controller
{
/**
* @inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => \yii\web\AccessControl::className(),
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login', 'error'],
......@@ -28,6 +34,9 @@ class SiteController extends Controller
];
}
/**
* @inheritdoc
*/
public function actions()
{
return [
......
......@@ -5,7 +5,7 @@ use yii\widgets\ActiveForm;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var common\models\LoginForm $model
* @var \common\models\LoginForm $model
*/
$this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title;
......
<?php
namespace common\models;
use Yii;
use common\models\User;
use yii\base\Model;
use Yii;
/**
* LoginForm is the model behind the login form.
* Login form
*/
class LoginForm extends Model
{
......@@ -17,7 +17,7 @@ class LoginForm extends Model
private $_user = false;
/**
* @return array the validation rules.
* @inheritdoc
*/
public function rules()
{
......
......@@ -6,8 +6,7 @@ use yii\helpers\Security;
use yii\web\IdentityInterface;
/**
* Class User
* @package common\models
* User model
*
* @property integer $id
* @property string $username
......@@ -19,19 +18,30 @@ use yii\web\IdentityInterface;
* @property integer $status
* @property integer $created_at
* @property integer $updated_at
* @property string $password write-only password
*/
class User extends ActiveRecord implements IdentityInterface
{
/**
* @var string the raw password. Used to collect password input and isn't saved in database
*/
public $password;
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const ROLE_USER = 10;
public static function create($attributes)
{
/** @var User $user */
$user = new static();
$user->setAttributes($attributes);
if ($user->save()) {
return $user;
} else {
return null;
}
}
/**
* @inheritdoc
*/
public function behaviors()
{
return [
......@@ -46,10 +56,7 @@ class User extends ActiveRecord implements IdentityInterface
}
/**
* Finds an identity by the given ID.
*
* @param string|integer $id the ID to be looked for
* @return IdentityInterface|null the identity object that matches the given ID.
* @inheritdoc
*/
public static function findIdentity($id)
{
......@@ -68,7 +75,7 @@ class User extends ActiveRecord implements IdentityInterface
}
/**
* @return int|string|array current user ID
* @inheritdoc
*/
public function getId()
{
......@@ -76,7 +83,7 @@ class User extends ActiveRecord implements IdentityInterface
}
/**
* @return string current user auth key
* @inheritdoc
*/
public function getAuthKey()
{
......@@ -84,8 +91,7 @@ class User extends ActiveRecord implements IdentityInterface
}
/**
* @param string $authKey
* @return boolean if auth key is valid for current user
* @inheritdoc
*/
public function validateAuthKey($authKey)
{
......@@ -93,6 +99,8 @@ class User extends ActiveRecord implements IdentityInterface
}
/**
* Validates password
*
* @param string $password password to validate
* @return bool if password provided is valid for current user
*/
......@@ -101,6 +109,35 @@ class User extends ActiveRecord implements IdentityInterface
return Security::validatePassword($password, $this->password_hash);
}
/**
* Generates password hash from password and sets it to the model
*
* @param string $password
*/
public function setPassword($password)
{
$this->password_hash = Security::generatePasswordHash($password);
}
/**
* Generates new password reset token
*/
public function generatePasswordResetToken()
{
$this->password_reset_token = Security::generateRandomKey();
}
/**
* Removes password reset token
*/
public function removePasswordResetToken()
{
$this->password_reset_token = '';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
......@@ -117,34 +154,7 @@ class User extends ActiveRecord implements IdentityInterface
['email', 'filter', 'filter' => 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'unique', 'message' => 'This email address has already been taken.', 'on' => 'signup'],
['email', 'exist', 'message' => 'There is no user with such email.', 'on' => 'requestPasswordResetToken'],
['password', 'required'],
['password', 'string', 'min' => 6],
];
}
public function scenarios()
{
return [
'signup' => ['username', 'email', 'password', '!status', '!role'],
'resetPassword' => ['password'],
'requestPasswordResetToken' => ['email'],
['email', 'unique'],
];
}
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if (($this->isNewRecord || $this->getScenario() === 'resetPassword') && !empty($this->password)) {
$this->password_hash = Security::generatePasswordHash($this->password);
}
if ($this->isNewRecord) {
$this->auth_key = Security::generateRandomKey();
}
return true;
}
return false;
}
}
<?php
namespace frontend\controllers;
use Yii;
use yii\web\Controller;
use common\models\LoginForm;
use frontend\models\PasswordResetRequestForm;
use frontend\models\ResetPasswordForm;
use frontend\models\SignupForm;
use frontend\models\ContactForm;
use common\models\User;
use yii\base\InvalidParamException;
use yii\web\BadRequestHttpException;
use yii\helpers\Security;
use yii\web\Controller;
use Yii;
/**
* Site controller
*/
class SiteController extends Controller
{
/**
* @inheritdoc
*/
public function behaviors()
{
return [
......@@ -34,6 +41,9 @@ class SiteController extends Controller
];
}
/**
* @inheritdoc
*/
public function actions()
{
return [
......@@ -59,7 +69,7 @@ class SiteController extends Controller
}
$model = new LoginForm();
if ($model->load($_POST) && $model->login()) {
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
......@@ -94,13 +104,15 @@ class SiteController extends Controller
public function actionSignup()
{
$model = new User();
$model->setScenario('signup');
if ($model->load($_POST) && $model->save()) {
if (Yii::$app->getUser()->login($model)) {
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
$user = $model->signup();
if ($user) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
......@@ -109,16 +121,14 @@ class SiteController extends Controller
public function actionRequestPasswordReset()
{
$model = new User();
$model->scenario = 'requestPasswordResetToken';
if ($model->load($_POST) && $model->validate()) {
if ($this->sendPasswordResetEmail($model->email)) {
$model = new PasswordResetRequestForm();
if ($model->load(Yii::$app->request->post()) && $model->sendEmail()) {
Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.');
return $this->goHome();
} else {
Yii::$app->getSession()->setFlash('error', 'There was an error sending email.');
}
}
return $this->render('requestPasswordResetToken', [
'model' => $model,
]);
......@@ -126,21 +136,13 @@ class SiteController extends Controller
public function actionResetPassword($token)
{
if (empty($token) || is_array($token)) {
throw new BadRequestHttpException('Invalid password reset token.');
try {
$model = new ResetPasswordForm($token);
} catch (InvalidParamException $e) {
throw new BadRequestHttpException($e->getMessage());
}
$model = User::find([
'password_reset_token' => $token,
'status' => User::STATUS_ACTIVE,
]);
if ($model === null) {
throw new BadRequestHttpException('Wrong password reset token.');
}
$model->scenario = 'resetPassword';
if ($model->load($_POST) && $model->save()) {
if ($model->load($_POST) && $model->resetPassword()) {
Yii::$app->getSession()->setFlash('success', 'New password was saved.');
return $this->goHome();
}
......@@ -149,27 +151,4 @@ class SiteController extends Controller
'model' => $model,
]);
}
private function sendPasswordResetEmail($email)
{
$user = User::find([
'status' => User::STATUS_ACTIVE,
'email' => $email,
]);
if (!$user) {
return false;
}
$user->password_reset_token = Security::generateRandomKey();
if ($user->save(false)) {
return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user])
->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
->setTo($email)
->setSubject('Password reset for ' . \Yii::$app->name)
->send();
}
return false;
}
}
<?php
namespace frontend\models;
use common\models\User;
use yii\base\Model;
/**
* Password reset request form
*/
class PasswordResetRequestForm extends Model
{
public $email;
/**
* @inheritdoc
*/
public function rules()
{
return [
['email', 'filter', 'filter' => 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'exist', 'targetClass' => 'User', 'message' => 'There is no user with such email.'],
];
}
/**
*
* @return boolean sends an email
*/
public function sendEmail()
{
/** @var User $user */
$user = User::find([
'status' => User::STATUS_ACTIVE,
'email' => $this->email,
]);
if (!$user) {
return false;
}
$user->generatePasswordResetToken();
if ($user->save()) {
return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user])
->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
->setTo($this->email)
->setSubject('Password reset for ' . \Yii::$app->name)
->send();
}
return false;
}
}
\ No newline at end of file
<?php
namespace frontend\models;
use common\models\User;
use yii\base\InvalidParamException;
use yii\base\Model;
use Yii;
/**
* Password reset form
*/
class ResetPasswordForm extends Model
{
public $password;
/**
* @var \common\models\User
*/
private $_user;
/**
* Creates a form model given a token
*
* @param string $token
* @param array $config name-value pairs that will be used to initialize the object properties
* @throws \yii\base\InvalidParamException if token is empty or not valid
*/
public function __construct($token, $config = [])
{
if (empty($token) || !is_string($token)) {
throw new InvalidParamException('Password reset token cannot be blank.');
}
$this->_user = User::find([
'password_reset_token' => $token,
'status' => User::STATUS_ACTIVE,
]);
if (!$this->_user) {
throw new InvalidParamException('Wrong password reset token.');
}
parent::__construct($config);
}
/**
* @return array the validation rules.
*/
public function rules()
{
return [
['password', 'required'],
['password', 'string', 'min' => 6],
];
}
/**
* Resets password.
* @return boolean if password was reset.
*/
public function resetPassword()
{
$user = $this->_user;
$user->password = $this->password;
$user->removePasswordResetToken();
return $user->save();
}
}
\ No newline at end of file
<?php
namespace frontend\models;
use common\models\User;
use yii\base\Model;
use Yii;
/**
* Signup form
*/
class SignupForm extends Model
{
public $username;
public $email;
public $password;
/**
* @inheritdoc
*/
public function rules()
{
return [
['username', 'filter', 'filter' => 'trim'],
['username', 'required'],
['username', 'string', 'min' => 2, 'max' => 255],
['email', 'filter', 'filter' => 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'unique', 'targetClass' => 'User', 'message' => 'This email address has already been taken.'],
['password', 'required'],
['password', 'string', 'min' => 6],
];
}
/**
* Signs user up.
* @return User saved model
*/
public function signup()
{
if ($this->validate()) {
return User::create($this->attributes);
}
return null;
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ use yii\captcha\Captcha;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var frontend\models\ContactForm $model
* @var \frontend\models\ContactForm $model
*/
$this->title = 'Contact';
$this->params['breadcrumbs'][] = $this->title;
......
......@@ -5,7 +5,7 @@ use yii\widgets\ActiveForm;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var common\models\LoginForm $model
* @var \common\models\LoginForm $model
*/
$this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title;
......
......@@ -5,7 +5,7 @@ use yii\widgets\ActiveForm;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var common\models\User $model
* @var \frontend\models\PasswordResetRequestForm $model
*/
$this->title = 'Request password reset';
$this->params['breadcrumbs'][] = $this->title;
......
......@@ -5,7 +5,7 @@ use yii\widgets\ActiveForm;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var common\models\User $model
* @var \frontend\models\ResetPasswordForm $model
*/
$this->title = 'Reset password';
$this->params['breadcrumbs'][] = $this->title;
......
......@@ -5,7 +5,7 @@ use yii\widgets\ActiveForm;
/**
* @var yii\web\View $this
* @var yii\widgets\ActiveForm $form
* @var common\models\User $model
* @var \frontend\models\SignupForm $model
*/
$this->title = 'Signup';
$this->params['breadcrumbs'][] = $this->title;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment