nordsoftware/yii2-account

View on GitHub
src/controllers/SignupController.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
/*
 * This file is part of Account.
 *
 * (c) 2014 Nord Software
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace nord\yii\account\controllers;

use nord\yii\account\components\datacontract\DataContract;
use nord\yii\account\filters\ClientAuthFilter;
use nord\yii\account\filters\SignupFilter;
use nord\yii\account\filters\TokenFilter;
use nord\yii\account\models\SignupForm;
use nord\yii\account\Module;
use Yii;
use yii\db\ActiveRecord;
use yii\filters\AccessControl;

class SignupController extends Controller
{
    // Event types.
    const EVENT_AFTER_ACTIVATION = 'afterActivation';
    const EVENT_AFTER_SIGNUP = 'afterSignup';

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            [
                'class' => SignupFilter::className(),
                'only' => ['index'],
            ],
            [
                'class' => AccessControl::className(),
                'denyCallback' => [$this, 'goHome'],
                'rules' => [
                    [
                        'actions' => ['activate', 'connect', 'done', 'index'],
                        'allow' => true,
                        'roles' => ['?'],
                    ],
                ],
            ],
            [
                'class' => TokenFilter::className(),
                'only' => ['activate'],
            ],
            [
                'class' => ClientAuthFilter::className(),
                'only' => ['connect'],
            ]
        ];
    }

    /**
     * Displays the sign up page.
     */
    public function actionIndex()
    {
        $scenario = $this->module->enableCaptcha ? 'captcha' : 'default';
        $dataContract = $this->module->getDataContract();

        /** @var SignupForm $model */
        $model = $dataContract->createSignupForm(['scenario' => $scenario]);

        if ($model->load(Yii::$app->request->post()) && $model->signup()) {
            $this->afterSignup();

            $account = $dataContract->findAccount([$this->module->emailAttribute => $model->email]);

            if ($this->module->enableActivation) {
                $this->sendActivationMail($account);
            } else {
                $dataContract->activateAccount($account);
                Yii::$app->session->setFlash($this->module->flashMessageKey, Module::t('flash', 'Sign up successful.'));
            }

            return $this->redirect($this->module->getRedirectUrl(Module::REDIRECT_SIGNUP));
        } else {
            return $this->render('index', [
                'model' => $model,
                'captchaClass' => $this->module->getClassName(Module::CLASS_CAPTCHA),
            ]);
        }
    }

    /**
     * Activates an account.
     *
     * @param string $token authentication token.
     * @return \yii\web\Response
     */
    public function actionActivate($token)
    {
        $tokenModel = $this->loadToken(Module::TOKEN_ACTIVATE, $token);

        $dataContract = $this->module->getDataContract();
        $account = $dataContract->findAccount($tokenModel->accountId);

        if ($account === null) {
            $this->pageNotFound();
        }

        $dataContract->activateAccount($account);
        $dataContract->useToken($tokenModel);

        $this->afterActivate();

        Yii::$app->session->setFlash($this->module->flashMessageKey, Module::t('flash', 'Account activated.'));
        return $this->redirect($this->module->getRedirectUrl(Module::REDIRECT_ACTIVATE));
    }

    /**
     * Displays the 'connect' page.
     *
     * @param string $providerId provider identifier.
     * @return string|\yii\web\Response
     */
    public function actionConnect($providerId)
    {
        $dataContract = $this->module->getDataContract();
        $provider = $dataContract->findProvider($providerId);

        if ($provider === null || !empty($provider->accountId)) {
            $this->pageNotFound();
        }

        $model = $dataContract->createConnectForm();

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            $account = $dataContract->createAccount([
                'attributes' => [
                    $this->module->usernameAttribute => $model->username,
                    $this->module->emailAttribute => $model->email,
                    $this->module->passwordAttribute => $this->module->getTokenGenerator()->generate(),
                ],
            ]);

            if (!$account->save()) {
                $this->fatalError();
            }

            $provider->updateAttributes(['accountId' => $account->id]);
            $this->afterSignup();
            Yii::$app->user->login($account, Module::getParam(Module::PARAM_LOGIN_EXPIRE_TIME));
            return $this->redirect($this->module->getRedirectUrl(Module::REDIRECT_CONNECT));
        } else {
            return $this->render('connect', ['model' => $model, 'provider' => $provider]);
        }
    }

    /**
     * Triggers the 'after signup' event.
     */
    public function afterSignup()
    {
        $this->trigger(self::EVENT_AFTER_SIGNUP);
    }

    /**
     * Triggers the 'after activate' event.
     */
    public function afterActivate()
    {
        $this->trigger(self::EVENT_AFTER_ACTIVATION);
    }

    /**
     * Displays the sign up done page.
     */
    public function actionDone()
    {
        return $this->render('done');
    }

    /**
     * Sends an activation email to owner of the given account.
     *
     * @param ActiveRecord $account account instance.
     */
    protected function sendActivationMail(ActiveRecord $account)
    {
        $token = $this->module->generateToken(Module::TOKEN_ACTIVATE, $account->id);
        $actionUrl = $this->module->createUrl([Module::URL_ROUTE_ACTIVATE, 'token' => $token], true);
        $this->module->getMailSender()->sendActivationMail([
            'to' => [$account->email],
            'from' => $this->module->getParam(Module::PARAM_FROM_EMAIL_ADDRESS),
            'subject' => Module::t('email', 'Thank you for signing up'),
            'data' => ['actionUrl' => $actionUrl],
        ]);
    }
}