contest-8.x-1.0-alpha2/src/Form/ContestViewForm.php
src/Form/ContestViewForm.php
<?php
namespace Drupal\contest\Form;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\Token;
use Drupal\contest\ContestHelper;
use Drupal\contest\ContestInterface;
use Drupal\contest\ContestStorage;
use Drupal\contest\ContestUser;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* The contest body, entry form and t&c with validation and submit.
*/
class ContestViewForm extends FormBase {
use ContestValidateTrait;
protected $cfgStore;
protected $contestStorage;
protected $mailMgr;
protected $request;
protected $token;
/**
* Class constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $cfgStore
* The config factory dependency injection.
* @param \Drupal\Core\Entity\EntityStorageInterface $contestStorage
* The contest storage dependency injection.
* @param \Drupal\Core\Mail\MailManagerInterface $mailMgr
* The mail manager dependency injection.
* @param Symfony\Component\HttpFoundation\RequestStack $request
* The request dependency injection.
* @param \Drupal\Core\Utility\Token $token
* The token service.
*/
public function __construct(ConfigFactoryInterface $cfgStore, EntityStorageInterface $contestStorage, MailManagerInterface $mailMgr, RequestStack $request, Token $token) {
$this->cfgStore = $cfgStore;
$this->contestStorage = $contestStorage;
$this->mailMgr = $mailMgr;
$this->request = $request;
$this->token = $token;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('entity.manager')->getStorage('contest'),
$container->get('plugin.manager.mail'),
$container->get('request_stack'),
$container->get('token')
);
}
/**
* The contest body, entry form and terms and conditions.
*
* @param array $form
* A Drupal form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A Drupal FormStateInterface object.
* @param \Drupal\contest\ContestInterface $contest
* The ContestInterface object.
* @param Symfony\Component\HttpFoundation\Request $request
* The Request object.
*
* @return array
* A Drupal form array.
*/
public function buildForm(array $form, FormStateInterface $form_state, ContestInterface $contest = NULL, Request $request = NULL) {
$fieldset_title = $this->t('Contestant Profile');
$states = ContestHelper::getStates($this->cfgStore->get('system.date')->get('country.default'));
$usr = new ContestUser($this->currentUser()->id());
// If the contest isn't running.
if (REQUEST_TIME < $contest->start->value || $contest->end->value < REQUEST_TIME) {
$form['body'] = [
'#type' => 'markup',
'#markup' => $contest->body->value,
'#weight' => -1,
];
// If results are published.
if (ContestStorage::getPublished($contest->id())) {
$form['results'] = [
'#type' => 'markup',
'#theme' => 'contest_results',
'#weight' => -1,
];
}
return $form;
}
$form['contest'] = [
'#type' => 'value',
'#value' => $contest,
];
$form['uid'] = [
'#type' => 'hidden',
'#value' => $usr->uid,
'#weight' => -10,
];
$form['cid'] = [
'#type' => 'hidden',
'#value' => $contest->id(),
'#weight' => -10,
];
$form['alert'] = [
'#type' => 'markup',
'#markup' => $usr->uid ? '' : '<p><b>' . $this->t('Please fill in and submit the form below, (all fields are required).') . '</b><br />' . $this->t('If you already have an account click @link to log in and skip filling in the form.', ['@link' => $this->l($this->t('here'), Url::fromRoute('user.login'))]) . '</p>',
'#weight' => -5,
];
$form['body'] = [
'#type' => 'markup',
'#markup' => $contest->body->value,
'#weight' => -1,
];
$form['fieldset'] = [
'#prefix' => "<div id=\"contest-profile-wrapper\"><fieldset><legend><a href=\"#\" id=\"contest-profile-toggle\">$fieldset_title<span class=\"contest-raquo\">»</span></a></legend><div id=\"contest-profile\" class=\"" . ($usr->completeProfile() ? 'complete-profile' : 'incomplete-profile') . '">',
'#suffix' => '</div></fieldset></div>',
'#type' => 'markup',
'#weight' => 2,
];
$form['fieldset']['contest_name'] = [
'#title' => $this->t('Name'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^\s*[\s\w\-\.]+\s*$'],
'#default_value' => $usr->fullName,
'#size' => 30,
'#maxlength' => 100,
'#required' => TRUE,
'#weight' => 0,
];
$form['fieldset']['contest_address'] = [
'#title' => $this->t('Address'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^.+$'],
'#default_value' => $usr->address,
'#size' => 30,
'#maxlength' => 100,
'#required' => TRUE,
'#weight' => 1,
];
$form['fieldset']['contest_city'] = [
'#title' => $this->t('City'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^\s*[\s\w\-\.]+\s*$'],
'#default_value' => $usr->city,
'#size' => 30,
'#maxlength' => 50,
'#required' => TRUE,
'#weight' => 2,
];
if (!empty($states)) {
$form['fieldset']['contest_state'] = [
'#title' => $this->t('State'),
'#type' => 'select',
'#attributes' => ['pattern' => '^.+$'],
'#options' => array_merge(['' => $this->t('-Select-')], $states),
'#default_value' => $usr->state,
'#required' => TRUE,
'#weight' => 3,
];
}
else {
$form['fieldset']['contest_state'] = [
'#title' => $this->t('Province'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^.+$'],
'#default_value' => $usr->state,
'#size' => 30,
'#maxlength' => 50,
'#required' => FALSE,
'#weight' => 3,
];
}
$form['fieldset']['contest_zip'] = [
'#title' => $this->t('Zip'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^\s*\d+\s*$'],
'#default_value' => $usr->zip,
'#size' => 30,
'#maxlength' => 5,
'#required' => TRUE,
'#weight' => 4,
];
$form['fieldset']['mail'] = [
'#title' => $this->t('Email'),
'#type' => 'textfield',
'#attributes' => ['pattern' => '^\s*[\w\-\.]+@[\w\-\.]+\.\w+\s*$'],
'#default_value' => !empty($usr->mail) ? $usr->mail : '',
'#size' => 30,
'#maxlength' => 100,
'#required' => TRUE,
'#weight' => 5,
];
$form['fieldset']['contest_phone'] = [
'#title' => $this->t('Phone'),
'#type' => 'textfield',
'#default_value' => $usr->phone,
'#size' => 30,
'#maxlength' => 20,
'#required' => FALSE,
'#weight' => 6,
];
$form['fieldset']['contest_birthdate'] = [
'#title' => $this->t('Birthday'),
'#description' => $this->t('Format: YYYY-MM-DD'),
'#type' => 'date',
'#default_value' => is_numeric($usr->birthdate) ? date('Y-m-d', $usr->birthdate) : '',
'#date_format' => 'Y-m-d',
'#date_increment' => ContestStorage::DAY,
'#date_label_position' => 'invisible',
'#date_timezone' => date('T'),
'#date_year_range' => '-100:+0',
'#required' => TRUE,
'#weight' => 7,
];
$form['contest_optin'] = [
'#title' => $this->t('Opt In'),
'#type' => 'checkbox',
'#description' => $this->t("I'd like to receive information about contests and special offers from the sponsor and promoter."),
'#attributes' => ['pattern' => '^\d$'],
'#prefix' => '<div id="contest-optin">',
'#suffix' => '</div>',
'#default_value' => 1,
'#required' => TRUE,
'#weight' => 8,
];
$form['clear_both'] = [
'#prefix' => '<div class="clr">',
'#suffix' => '</div>',
'#type' => 'markup',
'#value' => ' ',
'#weight' => 9,
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Enter Contest'),
'#weight' => 11,
];
$form['tnc_fieldset'] = [
'#theme' => 'contest_tnc',
'#data' => [
'title' => $this->t('Terms and Conditions'),
'tnc' => Xss::filter($this->token->replace($this->cfgStore->get('contest.tnc')->get('tnc'))),
],
'#weight' => 12,
];
return $form;
}
/**
* The form ID.
*
* @return string
* The form ID.
*/
public function getFormId() {
return 'contest_view_form';
}
/**
* Submit function for the contest entry form.
*
* @param array $form
* A drupal form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A Drupal FormStateInterface object.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$user = new ContestUser($this->currentUser()->id());
$periods = ContestStorage::getPeriodOptions();
// Users must have a complete profile to enter a contest.
$form_state->setValue('uid', $this->contestant($form_state));
$usr = new ContestUser($form_state->getValue('uid'));
// If Incomplete profile give explanation and redirect.
if ($user->uid != $usr->uid && !$usr->completeProfile()) {
drupal_set_message($this->t('You already have an account with an incomplete profile. The easiest way to enter the contest is to log in and come back and enter the contest.'), 'warning');
drupal_set_message($this->t("Once your profile is complete you won't have to do this again."));
drupal_set_message($this->t('If you have problems logging in click the "Request new password" link and a login link will be sent to your email.'));
return new RedirectResponse("/user");
}
// I don't think this should ever get used, but...
elseif (!$usr->completeProfile()) {
drupal_set_message($this->t('You must have a complete profile to enter a contest.'), 'warning');
return new RedirectResponse('/user/' . $usr->uid . '/edit');
}
// We'll check to see if the contest is running by getting the entry period.
$period = $this->contestStorage->getPeriod($form_state->getValue('cid'));
if (!$period) {
drupal_set_message($this->t('This contest is closed.'), 'warning');
return new RedirectResponse("/contest");
}
// Check to see if they've entered today.
$entered = $this->usrEntered($form_state->getValue('uid'), $form_state->getValue('cid'), $period);
if ($entered) {
$args = ['@period' => strtolower($periods[$period])];
drupal_set_message($this->t('You can enter the contest @period. We already have an entry for you during this period.', $args), 'warning');
return new RedirectResponse('/contest/' . $form_state->getValue('cid'));
}
// Enter them into the contest.
$fields = [
'cid' => $form_state->getValue('cid'),
'uid' => $usr->uid,
'created' => REQUEST_TIME,
'ip' => $this->request->getCurrentRequest()->getClientIp(),
];
$this->contestStorage->saveEntry($fields);
drupal_set_message($this->t('Your you have been entered into the contest.'));
}
/**
* Validation function for the contest entry form.
*
* @param array $form
* A drupal form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A Drupal FormStateInterface object.
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
}
/**
* Find or add a contestant then return the uid.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A Drupal FormStateInterface object.
*
* @return int
* The entrant's user ID.
*/
protected function contestant(FormStateInterface $form_state) {
$user = new ContestUser($this->currentUser()->id());
$usr = new ContestUser($form_state->getValue('uid'));
// If no user try to get the user by email.
if (!$usr->uid) {
$usr = ContestUser::loadByMail($form_state->getValue('mail'));
}
// If we have them and the match the global user update their information.
if ($usr->uid && $usr->uid == $user->uid) {
$this->usrSave($usr, $form_state);
return $usr->uid;
}
// If we have a valid user return their ID.
elseif ($usr->uid) {
return $usr->uid;
}
// If they don't exist, create them.
$usr = ContestUser::create($form_state->getValue('contest_name'), $form_state->getValue('mail'));
$this->usrSave($usr, $form_state);
// Build message variables, send welcome email and set welcome message.
$acct = $usr->getAccount();
$mail = $this->mailMgr->mail('user', 'register_no_approval_required', $usr->mail, $usr->lang, ['account' => $acct], ContestHelper::getSiteMail());
if (empty($mail)) {
drupal_set_message($this->t("There was an error sending your confirmation email."), 'error');
}
$tokens = [
'@password' => $usr->pass,
'@site_name' => $this->cfgStore->get('system.site')->get('name'),
'@username' => $usr->name,
];
drupal_set_message($this->t("You have been added to the @site_name website. Below is your login information.<br>Username: @username<br>Password: @password.<br>Please keep this information for you records. If you have a problem logging in, use the password recovery tool located at the top of the user's login page.", $tokens));
user_login_finalize($acct);
return $usr->uid;
}
/**
* Return true if entered in the contest during this period, (configuarble).
*
* @param int $uid
* The user's ID.
* @param int $cid
* The node ID.
* @param int $period
* The seconds allowed between entries.
*
* @return bool
* True if the user has entered the contest already during this period.
*/
protected function usrEntered($uid, $cid, $period) {
$fmt = ContestStorage::getPeriodFormats();
$periods = ContestStorage::getPeriodOptions();
// If it's a one entry contest check for an entry and return.
if ($periods[$period] == $this->t('Once')) {
return $this->contestStorage->usrEnteredOnce($cid, $uid);
}
// If we can't figure out the format, we'll assume TRUE.
if (empty($fmt[$period])) {
return TRUE;
}
// Determine if the user has already enter the contest.
$today = date($fmt[$period], REQUEST_TIME);
$entered = date($fmt[$period], $this->contestStorage->latestUsrEntryDate($cid, $uid));
return ($entered >= $today) ? TRUE : FALSE;
}
/**
* Save the contest profile fields to the user object.
*
* @param \Drupal\contest\ContestUser $usr
* A ContestUser object.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A Drupal FormStateInterface object.
*/
protected function usrSave(ContestUser $usr, FormStateInterface $form_state) {
if (empty($usr->uid)) {
return;
}
$usr->fullName = $form_state->getValue('contest_name');
$usr->address = $form_state->getValue('contest_address');
$usr->city = $form_state->getValue('contest_city');
$usr->state = $form_state->getValue('contest_state');
$usr->zip = $form_state->getValue('contest_zip');
$usr->phone = $form_state->getValue('contest_phone');
$usr->birthdate = strtotime($form_state->getValue('contest_birthdate'));
$usr->optin = $form_state->getValue('contest_optin');
$usr->save();
}
}
