email_confirmer-8.x-1.x-dev/src/Form/EmailConfirmerResponseForm.php
src/Form/EmailConfirmerResponseForm.php
<?php
namespace Drupal\email_confirmer\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\email_confirmer\InvalidConfirmationStateException;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Email confirmation response form.
*/
class EmailConfirmerResponseForm extends EntityConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->config('email_confirmer.settings')
->get('confirmation_response.questions.' . $this->entity->getStatus());
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
/** @var \Drupal\email_confirmer\EmailConfirmationInterface $confirmation */
$confirmation = $this->getEntity();
return $confirmation->isPending() ? $this->t('Send') : $this->t('OK');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('<front>');
}
/**
* {@inheritdoc}
*/
public function getFormName() {
return $this->getFormId();
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'email_confirmer_response';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Skip the response form and positively confirm the confirmation according
// to the settings.
if ($this->config('email_confirmer.settings')
->get('confirmation_response.skip_confirmation_form')) {
return $this->skipConfirmationForm($form_state);
}
// Build the response form.
$form = parent::buildForm($form, $form_state);
unset($form['#process']);
unset($form['#after_build']);
// No cancel option needed.
unset($form['actions']['cancel']);
if ($this->getEntity()->isPending()) {
$form['cancel'] = [
'#type' => 'radios',
'#default_value' => 0,
'#options' => [
0 => $this->t('Confirm'),
1 => $this->t('Cancel'),
],
];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
/** @var \Drupal\email_confirmer\EmailConfirmationInterface $confirmation */
$confirmation = $this->getEntity();
$question = '';
switch ($confirmation->getStatus()) {
case 'pending':
// @todo obfuscate email address if no administer permission, user is anonymous or not owner
$question = $this->t('Confirm %email', ['%email' => $this->entity->label()]);
break;
case 'expired':
if ($confirmation->isConfirmed() || $confirmation->isCancelled()) {
$question = $this->t('Already processed');
}
else {
$question = $this->t('Confirmation expired');
}
break;
case 'cancelled':
$question = $this->t('Confirmation cancelled');
break;
case 'confirmed':
$question = $this->t('Confirmation done');
break;
}
return $question;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Do nothing if it is not a real response.
if (!$this->getEntity()->isPending()) {
$form_state->setRedirectUrl($this->getRedirectUrl('error'));
return;
}
try {
if ($form_state->getValue('cancel')) {
// Explicitly cancelled.
$this->cancelConfirmation($form_state);
}
else {
// Confirmed.
$this->confirmConfirmation($form_state);
}
}
catch (InvalidConfirmationStateException $exception) {
$this->confirmationError($form_state);
}
}
/**
* Cancels the email confirmation.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @throws \Drupal\email_confirmer\InvalidConfirmationStateException
* If confirmation is expired, confirmed or already cancelled.
*/
protected function cancelConfirmation(FormStateInterface $form_state) {
/** @var \Drupal\email_confirmer\EmailConfirmationInterface $confirmation */
$confirmation = $this->getEntity();
$confirmation->cancel();
$this->messenger()->addStatus($this->t('Email confirmation cancelled.'));
$confirmation->save();
$form_state->setRedirectUrl($this->getRedirectUrl('cancel'));
}
/**
* Confirms the email confirmation.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @throws \Drupal\email_confirmer\InvalidConfirmationStateException
* If confirmation is cancelled, expired or already confirmed.
*/
protected function confirmConfirmation(FormStateInterface $form_state) {
/** @var \Drupal\email_confirmer\EmailConfirmationInterface $confirmation */
$confirmation = $this->getEntity();
if (!$confirmation->confirm($this->getRouteMatch()->getParameter('hash'))) {
$this->confirmationError($form_state);
return;
}
$this->messenger()->addStatus($this->t('Email confirmation confirmed.'));
$confirmation->save();
$form_state->setRedirectUrl($this->getRedirectUrl('confirm'));
}
/**
* Common behaviour when there ware errors in confirmation.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
protected function confirmationError(FormStateInterface $form_state) {
$this->messenger()->addError($this->t('There was an error processing your email confirmation.'), 'error');
$form_state->setRedirectUrl($this->getRedirectUrl('error'));
}
/**
* Returns the URL to redirect to after the form is completed or skipped.
*
* @param string $operation
* Possible values:
* - confirm
* - cancel
* - error
* Defines the page that will be redirected to.
*
* @return \Drupal\Core\Url
* The url to redirect to.
*/
protected function getRedirectUrl($operation) {
/** @var \Drupal\email_confirmer\EmailConfirmationInterface $confirmation */
$confirmation = $this->getEntity();
// Go to confirmation response URL, response path from settings or front.
if (!$url = $confirmation->getResponseUrl($operation)) {
$path = $this->config('email_confirmer.settings')
->get('confirmation_response.url.' . $operation) ?: '<front>';
$url = Url::fromUri('internal:/' . $path);
}
return $url;
}
/**
* Skip the response form and positively confirm the confirmation.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* Redirection response according to the confirmation result.
*/
protected function skipConfirmationForm(FormStateInterface $form_state) {
try {
$this->confirmConfirmation($form_state);
}
catch (InvalidConfirmationStateException $exception) {
$this->confirmationError($form_state);
}
// Use RedirectResponse because redirecting with form state is not working
// inside buildForm.
$redirect_state = $form_state->getRedirect()
?: $this->getRedirectUrl('error');
if ($redirect_state instanceof RedirectResponse) {
$redirect_response = $redirect_state;
}
else {
$redirect_response = new RedirectResponse($redirect_state instanceof Url
? $redirect_state->setAbsolute()->toString()
: $redirect_state);
}
return $redirect_response;
}
}
