Register > Start
* @copyright Tamaranga
*/
class Start extends AuthForm
{
/** @var string */
public $title = '';
/** @var string */
public $back = '';
/** @var bool */
public $pass_confirm = false;
/** @var string */
public $captcha = '0';
/** @var string */
public $captcha_key = 'users-auth-register';
public function init()
{
parent::init();
$this->setKey('users-auth-register');
$this->setTemplate('register/start', 'users');
$this->setTitle(_t('@users', 'Registration Form'));
}
public function data()
{
$data = parent::data();
if ($this->request->user()) {
return Users::redirectToAccountSettings();
}
if (empty($this->back)) {
$data['back'] = $this->request->referer($this->router->url('index'));
}
$data['email_on'] = $this->hasEmail();
$data['phone_on'] = $this->hasPhoneNumber();
$data['agreement_on'] = $this->hasAgreement();
$data['agreement_url'] = Users::url('agreement');
$data['password_on'] = $this->hasPassword();
$data['password_confirm_on'] = $this->hasPasswordConfirm();
$data['captcha_on'] = $this->hasCaptcha();
$data['providers'] = Users::social()->getProvidersEnabled();
$data['login_url'] = $this->loginUrl();
$data['login_social_url'] = Users::url('login.social');
return $data;
}
public function validate($data = [])
{
$data = $this->validateUsingRules($data, [
'phone_number' => [TYPE_NOTAGS, 'limit' => 30], # Phone number
'email' => [TYPE_NOTAGS, 'limit' => 100], # E-mail
'password' => [TYPE_NOTRIM], # Password
'password2' => [TYPE_NOTRIM], # Password confirmation
'agreement' => [TYPE_BOOL], # Agreement confirmation
]);
do {
# Email
if ($this->hasEmail()) {
if (! $this->validateEmail($data['email'])) {
break;
}
if ($this->isEmailExists($data['email'])) {
$this->errors->set(
_t('users', 'A user with this email address is already registered. Forgot password?', [
'link_forgot' => 'href="' . $this->forgotUrl() . '"'
]),
'email'
);
break;
}
}
# Phone
if ($this->hasPhoneNumber()) {
if (! $this->validatePhone($data['phone_number'])) {
break;
}
if ($this->isPhoneExists($data['phone_number'])) {
$this->errors->set(
_t('users', 'A user with this phone number is already registered. Forgot password?', [
'link_forgot' => 'href="' . $this->forgotUrl() . '"',
]),
'phone_number'
);
break;
}
}
# Password
if ($this->hasPassword()) {
if (empty($data['password'])) {
$this->errors->set(_t('users', 'Enter password'), 'password');
break;
}
if (! $this->security->validatePassword($data['password'])) {
break;
}
if (
$this->hasPasswordConfirm() &&
(empty($data['password2']) || $data['password'] !== $data['password2'])
) {
$this->errors->set(_t('users', 'Incorrect password confirmation'), 'password2');
break;
}
}
# Blocks
$data = $this->validateBlocks($data);
if ($this->errors->any()) {
break;
}
# Captcha
if ($this->hasCaptcha()) {
if (! $this->isCaptchaValid($this->captcha_key)) {
break;
}
}
# Agreement
if (! $this->validateAgreement($data['agreement'])) {
break;
}
} while (false);
# Only data to store in database
unset($data['agreement'], $data['password2']);
if ($this->phoneOnly()) {
unset($data['email']);
}
if ($this->emailOnly()) {
unset($data['phone_number']);
}
if (! $this->hasPassword()) {
unset($data['password']);
}
return $data;
}
public function submit()
{
do {
if ($this->request->user()) {
$this->respond('redirect', $this->router->url('index'));
break;
}
if (! $this->security->validateReferer()) {
$this->errors->reloadPage();
break;
}
$data = $this->validate();
if ($this->errors->any()) {
break;
}
if ($this->tooManyRequests($this->getKey(), 10)) {
break;
}
$registered = $this->registerAndNotify($data);
if (empty($registered)) {
break;
}
# Store data for next steps
$this->startData($registered);
# Response
$this->respond('success', true);
if ($this->emailOnly()) {
$this->respond('redirect', $this->registrationUrl('emailed'));
} else {
$this->respond('redirect', $this->registrationUrl('phone'));
}
} while (false);
# Preserve Return url
$this->respond('back', $this->request->post('back', TYPE_NOTAGS));
return parent::submit();
}
/**
* Validate data and register user
* @param array $data to create user account [?email, ?phone_number, ?password, ...]
* @return array|bool registered data or false (something went wrong)
*/
public function registerAndNotify(array $data = []): array
{
$response = false;
do {
$email = $data['email'] ?? '';
$phone = $data['phone_number'] ?? '';
# Create new user account
$user = Users::userRegister($data);
if (empty($user)) {
$this->errors->set(_t('users', 'Registration error, contact the administrator'));
break;
}
$userId = $user['user_id'];
$password = $user['password'];
# Send confirmation notification via email/sms
$response = [
'id' => $userId,
'password' => $password,
'activate_link' => $user['activate_link'],
];
if ($this->emailOnly()) {
# Send email notification with link (activate_link) (validate on "Activate" step)
Users::sendEmailRegistrationConfirmation($userId, $email, $password, $user['activate_link']);
} elseif ($this->phoneOnly()) {
$password = $this->updateUserPassword($userId, $user['activate_key']);
# Send activation key as password via sms (validate on "PhoneConfirmation" step)
Users::sms(false)->sendPassword($phone, $password);
} elseif ($this->phoneAndEmail()) {
# Send activation code via sms (validate on "PhoneConfirmation" step)
Users::sms(false)->sendActivationCode($phone, $user['activate_key']);
}
} while (false);
return $response;
}
/**
* Use email field in form
* @return bool
*/
public function hasEmail()
{
return (
$this->emailOnly() ||
$this->phoneAndEmail()
);
}
/**
* Use phone number field in form
* @return bool
*/
public function hasPhoneNumber()
{
return (
$this->phoneOnly() ||
$this->phoneAndEmail()
);
}
/**
* Use password field in form
* @return bool
*/
public function hasPassword()
{
return ! $this->phoneOnly();
}
/**
* Use password confirmation field in form
* @return bool
*/
public function hasPasswordConfirm()
{
if ($this->hasPassword()) {
return $this->pass_confirm;
}
return false;
}
/**
* Use captcha field in form
* @return bool
*/
public function hasCaptcha()
{
return Captcha::enabled($this->captcha_key);
}
/**
* @inheritdoc
*/
public function settingsForm($form)
{
$form->text('title', _t('@site', 'Form Title'), _t('users', 'Registration', true));
$form->checkbox('pass_confirm', _t('@users', 'Password confirmation'), $this->pass_confirm)
->tip(_t('@users', 'Show the repeat password field in the registration form'));
$form->select('captcha', _t('@users', 'Captcha at Sign Up'), $this->captcha, function () {
return Captcha::actionDriverOptions();
})
->sysAdmin('captcha.enabled.' . $this->captcha_key);
}
}