View source
<?php
namespace Drupal\forward\Form;
use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Flood\FloodInterface;
use Drupal\Core\Form\BaseFormIdInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Mail\MailManager;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountSwitcherInterface;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Utility\LinkGenerator;
use Drupal\Core\Utility\Token;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Component\Utility\Unicode;
use Drupal\forward\Event\EntityForwardEvent;
use Drupal\forward\Event\EntityPreforwardEvent;
use Symfony\Component\HttpFoundation\RequestStack;
class ForwardForm extends FormBase implements BaseFormIdInterface {
protected $entity;
protected $moduleHandler;
protected $entityTypeManager;
protected $requestStack;
protected $database;
protected $tokenService;
protected $floodInterface;
protected $accountSwitcher;
protected $renderer;
protected $eventDispatcher;
protected $mailer;
protected $linkGenerator;
protected $settings;
public function __construct(EntityInterface $entity) {
$this->entity = $entity;
}
public function injectServices(ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack, Connection $database, Token $token_service, FloodInterface $flood_interface, AccountSwitcherInterface $account_switcher, RendererInterface $renderer, ContainerAwareEventDispatcher $event_dispatcher, MailManager $mailer, LinkGenerator $link_generator) {
$this->moduleHandler = $module_handler;
$this->entityTypeManager = $entity_type_manager;
$this->requestStack = $request_stack;
$this->database = $database;
$this->tokenService = $token_service;
$this->floodInterface = $flood_interface;
$this->accountSwitcher = $account_switcher;
$this->renderer = $renderer;
$this->eventDispatcher = $event_dispatcher;
$this->mailer = $mailer;
$this->linkGenerator = $link_generator;
}
public function getFormId() {
return 'forward_form_' . $this->entity
->getEntityTypeId() . '_' . $this->entity
->id();
}
public function getBaseFormId() {
return 'forward_form';
}
protected function getEditableConfigNames() {
return [
'forward.form',
];
}
private function cleanString($string) {
$string = preg_replace('|https?://www\\.[a-z\\.0-9]+|i', '', $string);
$string = preg_replace('|www\\.[a-z\\.0-9]+|i', '', $string);
return $string;
}
private function getToken(FormStateInterface $form_state = NULL) {
$token = array();
if ($form_state && $form_state
->getValue('name')) {
$token = [
'forward' => [
'sender_name' => $this
->cleanString($form_state
->getValue('name')),
],
];
}
elseif ($this
->currentUser()
->isAuthenticated()) {
$token = [
'forward' => [
'sender_name' => $this
->currentUser()
->getDisplayName(),
],
];
}
if ($form_state && $form_state
->getValue('email')) {
$token['forward']['sender_email'] = $form_state
->getValue('email');
}
elseif ($this
->currentUser()
->isAuthenticated()) {
$token['forward']['sender_email'] = $this
->currentUser()
->getEmail();
}
if ($form_state) {
$token['forward']['entity'] = $form_state
->get('#entity');
}
if ($extra_tokens = $this->moduleHandler
->invokeAll('forward_token', array(
$form_state,
))) {
$token += $extra_tokens;
}
return $token;
}
private function getFloodControlEventName() {
return 'forward.send';
}
private function isValidDisplay(EntityInterface $entity, $view_mode) {
$valid = TRUE;
if ($entity
->getEntityType()
->hasKey('bundle')) {
$display_name = $entity
->getEntityTypeId() . '.' . $entity
->bundle() . '.' . $view_mode;
}
else {
$display_name = $entity
->getEntityTypeId() . '.' . $view_mode;
}
$display = $this->entityTypeManager
->getStorage('entity_view_display')
->load($display_name);
if ($display) {
$valid = FALSE;
if ($display
->status()) {
$valid = TRUE;
}
}
return $valid;
}
private function logEvent(EntityInterface $entity) {
$entity_type = $entity
->getEntityTypeId();
$bundle = $entity
->bundle();
$entity_id = $entity
->id();
$uid = $this
->currentUser()
->id();
$path = substr($entity
->toUrl()
->toString(), 1);
$ip_address = $this->requestStack
->getCurrentRequest()
->getClientIp();
$timestamp = REQUEST_TIME;
$this->database
->insert('forward_log')
->fields(array(
'type' => $entity_type,
'id' => $entity_id,
'path' => $path,
'action' => 'SENT',
'timestamp' => $timestamp,
'uid' => $uid,
'hostname' => $ip_address,
))
->execute();
$this->database
->merge('forward_statistics')
->key(array(
'type' => $entity_type,
'bundle' => $bundle,
'id' => $entity_id,
))
->fields(array(
'forward_count' => 1,
'last_forward_timestamp' => $timestamp,
))
->expression('forward_count', 'forward_count + 1')
->execute();
}
public function buildForm(array $form, FormStateInterface $form_state, array $settings = NULL) {
if (!$settings) {
$settings = $this
->config('forward.settings')
->get();
}
$this->settings = $settings;
$form_state
->set('#entity', $this->entity);
$token = $this
->getToken($form_state);
$langcode = $this->entity
->language()
->getId();
if ($settings['forward_interface_type'] == 'link') {
$form['#title'] = $this->tokenService
->replace($settings['forward_link_title'], $token, array(
'langcode' => $langcode,
));
}
else {
$form['message'] = array(
'#type' => 'details',
'#title' => $this->tokenService
->replace($settings['forward_link_title'], $token, array(
'langcode' => $langcode,
)),
'#description' => '',
'#open' => FALSE,
'#weight' => $settings['forward_interface_weight'],
);
}
$form['message']['instructions'] = array(
'#markup' => $this->tokenService
->replace($settings['forward_form_instructions'], $token, array(
'langcode' => $langcode,
)),
);
$form['message']['email'] = array(
'#type' => 'email',
'#title' => $this
->t('Your email address'),
'#maxlength' => 254,
'#required' => TRUE,
);
$form['message']['name'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Your name'),
'#maxlength' => 128,
'#required' => TRUE,
);
$form['message']['recipient'] = array(
'#type' => 'email',
'#title' => $this
->t('Send to'),
'#maxlength' => 254,
'#description' => $this
->t('Enter the email address of the recipient.'),
'#required' => TRUE,
);
if ($settings['forward_form_display_page']) {
$form['message']['page'] = array(
'#type' => 'item',
'#title' => $this
->t('You are going to email the following:'),
'#markup' => $this->linkGenerator
->generate($this->entity
->label(), $this->entity
->toUrl()),
);
}
if ($settings['forward_form_display_subject']) {
$form['message']['subject'] = array(
'#type' => 'item',
'#title' => $this
->t('The message subject will be:'),
'#markup' => $this->tokenService
->replace($settings['forward_email_subject'], $token, array(
'langcode' => $langcode,
)),
);
}
if ($settings['forward_form_display_body']) {
$form['message']['body'] = array(
'#type' => 'item',
'#title' => $this
->t('The introductory message text will be:'),
'#markup' => $this->tokenService
->replace($settings['forward_email_message'], $token, array(
'langcode' => $langcode,
)),
);
}
if ($settings['forward_personal_message']) {
$form['message']['message'] = array(
'#type' => 'textarea',
'#title' => $this
->t('Your personal message'),
'#default_value' => '',
'#cols' => 50,
'#rows' => 5,
'#description' => $settings['forward_personal_message_filter'] ? $this
->t('These HTML tags are allowed in this field: @tags.', array(
'@tags' => $settings['forward_personal_message_tags'],
)) : t('HTML is not allowed in this field.'),
'#required' => $settings['forward_personal_message'] == 2,
);
}
if ($settings['forward_interface_type'] == 'form') {
$form['message']['actions'] = array(
'#type' => 'actions',
);
$form['message']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this
->t('Send Message'),
'#weight' => 100,
);
}
else {
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this
->t('Send Message'),
);
}
if ($this
->currentUser()
->isAuthenticated()) {
if ($this
->currentUser()
->hasPermission('override email address')) {
$form['message']['email']['#default_value'] = $this
->currentUser()
->getEmail();
}
else {
$form['message']['email']['#type'] = 'hidden';
$form['message']['email']['#value'] = $this
->currentUser()
->getEmail();
}
$form['message']['name']['#default_value'] = $this
->currentUser()
->getDisplayName();
}
return $form;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
if (!$this
->currentUser()
->hasPermission('override flood control')) {
$event = $this
->getFloodControlEventName();
if (!$this->floodInterface
->isAllowed($event, $this->settings['forward_flood_control_limit'])) {
$message = new FormattableMarkup($this->settings['forward_flood_control_error'], [
'@number' => $this->settings['forward_flood_control_limit'],
]);
$form_state
->setErrorByName('', $message);
}
}
parent::validateForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$entity = $form_state
->get('#entity');
$recipient = $form_state
->getValue('recipient');
$langcode = $entity
->language()
->getId();
$switched = FALSE;
if ($this
->currentUser()
->isAuthenticated() && empty($this->settings['forward_bypass_access_control'])) {
$this->accountSwitcher
->switchTo(new AnonymousUserSession());
$switched = TRUE;
}
try {
$token = $this
->getToken($form_state);
$params['subject'] = $this->tokenService
->replace($this->settings['forward_email_subject'], $token, array(
'langcode' => $langcode,
));
$view_mode = '';
$elements = array();
if ($entity
->access('view')) {
$view_builder = $this->entityTypeManager
->getViewBuilder($entity
->getEntityTypeId());
$view_mode = 'forward';
if ($this
->isValidDisplay($entity, $view_mode)) {
$elements = $view_builder
->view($entity, $view_mode, $langcode);
}
if (empty($elements)) {
$view_mode = 'teaser';
if ($this
->isValidDisplay($entity, $view_mode)) {
$elements = $view_builder
->view($entity, $view_mode, $langcode);
}
}
if (empty($elements)) {
$view_mode = 'full';
$elements = $view_builder
->view($entity, $view_mode, $langcode);
}
}
$elements['#forward_build'] = TRUE;
$content = $this->renderer
->render($elements);
$header = [
'#markup' => $this->tokenService
->replace($this->settings['forward_email_message'], $token, array(
'langcode' => $langcode,
)),
];
$message = '';
if ($this->settings['forward_personal_message']) {
if ($this->settings['forward_personal_message_filter']) {
$raw_values = $form_state
->getUserInput();
$allowed_tags = explode(',', $this->settings['forward_personal_message_tags']);
$message = !empty($raw_values['message']) ? Xss::filter($raw_values['message'], $allowed_tags) : '';
$message = [
'#markup' => nl2br($message),
];
}
else {
$message = [
'#plain_text' => nl2br($form_state
->getValue('message')),
];
}
}
$render_array = array(
'#theme' => 'forward',
'#email' => $form_state
->getValue('email'),
'#header' => $header,
'#message' => $message,
'#settings' => $this->settings,
'#entity' => $entity,
'#content' => $content,
'#view_mode' => $view_mode,
);
$this->moduleHandler
->alter('forward_mail_pre_render', $render_array, $form_state);
$params['body'] = $this->renderer
->render($render_array);
if ($this->settings['forward_filter_format']) {
$params['body'] = check_markup($params['body'], $this->settings['forward_filter_format'], $langcode);
}
$this->moduleHandler
->alter('forward_mail_post_render', $params['body'], $form_state);
} catch (Exception $e) {
if ($switched) {
$this->accountSwitcher
->switchBack();
$switched = FALSE;
}
$this
->logger('forward')
->error($e
->getMessage());
}
if ($switched) {
$this->accountSwitcher
->switchBack();
}
$from = $this->settings['forward_email_from_address'];
if (empty($from)) {
$from = $this
->config('system.site')
->get('mail');
}
if (empty($from)) {
$site_mail = ini_get('sendmail_from');
}
$params['headers']['Reply-To'] = trim(Unicode::mimeHeaderEncode($form_state
->getValue('name')) . ' <' . $form_state
->getValue('email') . '>');
$account = $this->entityTypeManager
->getStorage('user')
->load($this
->currentUser()
->id());
$event = new EntityPreforwardEvent($account, $entity, [
'account' => $account,
'entity' => $entity,
]);
$this->eventDispatcher
->dispatch(EntityPreforwardEvent::EVENT_NAME, $event);
$key = 'send_entity';
$this->mailer
->mail('forward', $key, $recipient, $langcode, $params, $from);
$this
->logEvent($entity);
$event = $this
->getFloodControlEventName();
$this->floodInterface
->register($event);
$event = new EntityForwardEvent($account, $entity, [
'account' => $account,
'entity' => $entity,
]);
$this->eventDispatcher
->dispatch(EntityForwardEvent::EVENT_NAME, $event);
$this->moduleHandler
->invokeAll('forward_entity', array(
$account,
$entity,
$form_state,
));
$message = $this->tokenService
->replace($this->settings['forward_form_confirmation'], $token, array(
'langcode' => $langcode,
));
if ($message) {
drupal_set_message($message);
}
if ($this->settings['forward_interface_type'] == 'link') {
if (!$form_state
->getRedirect()) {
$form_state
->setRedirectUrl($entity
->toUrl());
}
}
}
}