| Server IP : 157.230.181.24 / Your IP : 216.73.217.11 Web Server : Apache/2.4.58 (Ubuntu) System : Linux conductive 6.8.0-117-generic #117-Ubuntu SMP PREEMPT_DYNAMIC Tue May 5 19:26:24 UTC 2026 x86_64 User : ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/vhosts/maxons/public/modules/contact_storage/ |
Upload File : |
<?php
/**
* @file
* Contains main module logic.
*/
use Drupal\contact\MessageForm;
use Drupal\contact_storage\Form\ContactFormDisableForm;
use Drupal\contact_storage\Form\ContactFormEnableForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\contact\ContactFormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\contact\Entity\ContactForm;
use Drupal\views\Views;
use Symfony\Component\Validator\Constraints\Url;
/**
* Implements hook_form_FORM_ID_alter() for contact_form_form().
*/
function contact_storage_form_contact_form_form_alter(&$form, FormStateInterface $form_state) {
/** @var \Drupal\contact\ContactFormInterface $contact_form */
$form_object = $form_state->getFormObject();
if (!in_array($form_object->getOperation(), ['edit', 'add'], TRUE)) {
// Only alter the edit and add forms.
return;
}
$contact_form = $form_object->getEntity();
$form['contact_storage_submit_text'] = [
'#type' => 'textfield',
'#title' => t('Submit button text'),
'#description' => t("Override the submit button's default <em>Send message</em> text."),
'#default_value' => $contact_form->getThirdPartySetting('contact_storage', 'submit_text', 'Send message'),
];
$form['contact_storage_url_alias'] = [
'#type' => 'textfield',
'#title' => t('Add URL alias'),
'#description' => t('Optionally add an URL alias to the contact form.'),
];
if (!$contact_form->isNew()) {
if ($alias = \Drupal::service('path.alias_storage')->load(['source' => '/' . $contact_form->toUrl('canonical')->getInternalPath()])) {
$form['contact_storage_url_alias']['#default_value'] = $alias['alias'];
}
}
$form['contact_storage_disabled_form_message'] = [
'#type' => 'textfield',
'#title' => t('Default disabled contact form message'),
'#description' => t('Default message to display if the contact form is disabled.'),
'#default_value' => $contact_form->getThirdPartySetting('contact_storage', 'disabled_form_message', t('This contact form has been disabled.')),
];
$form['contact_storage_preview'] = [
'#type' => 'checkbox',
'#title' => t('Allow preview'),
'#description' => t('Show the preview button?'),
'#default_value' => $contact_form->getThirdPartySetting('contact_storage', 'show_preview', TRUE),
];
$form['contact_storage_maximum_submissions_user'] = [
'#type' => 'textfield',
'#title' => t('Maximum submissions'),
'#description' => t('The maximum number of times, per user, the form can be submitted (0 for unlimited).'),
'#default_value' => $contact_form->getThirdPartySetting('contact_storage', 'maximum_submissions_user', 0),
];
$form['#entity_builders'][] = 'contact_storage_contact_form_form_builder';
$form['#validate'][] = 'contact_storage_contact_form_form_validate';
$form['actions']['submit']['#submit'][] = 'contact_storage_contact_form_form_submit';
}
/**
* Entity builder for the contact form edit form with third party options.
*
* @see contact_storage_test_form_contact_form_edit_form_alter()
*/
function contact_storage_contact_form_form_builder($entity_type, ContactFormInterface $contact_form, &$form, FormStateInterface $form_state) {
$contact_form->setThirdPartySetting('contact_storage', 'submit_text', $form_state->getValue('contact_storage_submit_text'));
$contact_form->setThirdPartySetting('contact_storage', 'show_preview', $form_state->getValue('contact_storage_preview'));
$contact_form->setThirdPartySetting('contact_storage', 'disabled_form_message', $form_state->getValue('contact_storage_disabled_form_message'));
$contact_form->setThirdPartySetting('contact_storage', 'maximum_submissions_user', $form_state->getValue('contact_storage_maximum_submissions_user'));
}
/**
* Contact form's form validation handler.
*
* @param array $form
* An associative array containing the structure of the form.
*
* @param \Drupal\Core\Form\FormStateInterface $formState
* The current state of the form.
*/
function contact_storage_contact_form_form_validate(&$form, FormStateInterface &$formState) {
// Validates the url alias. It has to start with a slash.
if (!empty($formState->getValue('contact_storage_url_alias'))) {
if (strpos($formState->getValue('contact_storage_url_alias'), '/') !== 0) {
$formState->setError($form['contact_storage_url_alias'], 'The alias path has to start with a slash.');
}
}
}
/**
* Contact form's form submission handler.
*
* @param array $form
* An associative array containing the structure of the form.
*
* @param \Drupal\Core\Form\FormStateInterface $formState
* The current state of the form.
*/
function contact_storage_contact_form_form_submit(&$form, FormStateInterface &$formState) {
$entity = $formState->getFormObject()->getEntity();
$old_alias = \Drupal::service('path.alias_storage')->load(['source' => '/' . $entity->toUrl('canonical')->getInternalPath()]);
$new_alias = $formState->getValue('contact_storage_url_alias');
// If there isn't an alias, set a new one.
if (!$old_alias) {
if ($new_alias) {
\Drupal::service('path.alias_storage')->save('/' . $entity->toUrl('canonical')->getInternalPath(), $formState->getValue('contact_storage_url_alias'));
}
}
else {
// Delete old alias if user erased it.
if ($old_alias && !$new_alias) {
\Drupal::service('path.alias_storage')->delete(['pid' => $old_alias['pid']]);
}
// Only save a non-empty alias.
elseif ($new_alias) {
\Drupal::service('path.alias_storage')->save('/' . $entity->toUrl('canonical')->getInternalPath(), $formState->getValue('contact_storage_url_alias'), LanguageInterface::LANGCODE_NOT_SPECIFIED, $old_alias['pid']);
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for contact_form_form().
*/
function contact_storage_form_contact_message_form_alter(&$form, &$form_state, $form_id) {
/** @var \Drupal\Core\Entity\ContentEntityForm $form_object */
$form_object = $form_state->getFormObject();
/* @var \Drupal\contact\MessageInterface $contact_message */
$contact_message = $form_object->getEntity();
$contact_form = ContactForm::load($contact_message->bundle());
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_mode */
if ($form_object instanceof MessageForm) {
if ($submit_text = $contact_form->getThirdPartySetting('contact_storage', 'submit_text', FALSE)) {
$form['actions']['submit']['#value'] = $submit_text;
}
if (!$contact_form->getThirdPartySetting('contact_storage', 'show_preview', TRUE)) {
$form['actions']['preview']['#access'] = FALSE;
}
}
// Check if the current user has reached the form's maximum submission limit.
$maximum_submissions_user = $contact_form->getThirdPartySetting('contact_storage', 'maximum_submissions_user', 0);
if (($maximum_submissions_user !== 0) && contact_storage_maximum_submissions_user($contact_form) >= $maximum_submissions_user) {
// Sets the error message.
$form['maximum_submissions_error'] = array(
'#type' => 'container',
'#markup' => t('You have reached the maximum submission limit of @limit for this form.', ['@limit' => $maximum_submissions_user]),
'#attributes' => array(
'class' => array('messages', 'messages--error'),
),
'#weight' => -100,
);
// Remove the submit and preview buttons.
$form['actions']['submit']['#access'] = FALSE;
$form['actions']['preview']['#access'] = FALSE;
}
}
/**
* Implements hook_entity_base_field_info().
*/
function contact_storage_entity_base_field_info(EntityTypeInterface $entity_type) {
if ($entity_type->id() == 'contact_message') {
$fields = array();
$fields['id'] = BaseFieldDefinition::create('integer')
->setLabel(t('Message ID'))
->setDescription(t('The message ID.'))
->setReadOnly(TRUE)
// Explicitly set this to 'contact' so that
// ContentEntityDatabaseStorage::usesDedicatedTable() doesn't attempt to
// put the ID in a dedicated table.
// @todo Remove when https://www.drupal.org/node/1498720 is in.
->setProvider('contact')
->setSetting('unsigned', TRUE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time that the message was created.'))
->setTranslatable(TRUE)
->setReadOnly(TRUE);
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('User ID'))
->setDescription(t('The user ID.'))
->setSetting('target_type', 'contact_form')
->setDefaultValueCallback('contact_storage_contact_message_default_uid');
$fields['ip_address'] = BaseFieldDefinition::create('string')
->setLabel(t('IP address'))
->setDescription(t('The IP address of the submitter.'))
->setDefaultValueCallback('contact_storage_contact_message_default_ip_address');
return $fields;
}
}
/**
* Default value callback for the contact message uid field.
*
* @return int
* The user ID.
*/
function contact_storage_contact_message_default_uid() {
return \Drupal::currentUser()->id();
}
/**
* Default value callback for the contact message ip_address field.
*
* @return int
* The client IP address.
*/
function contact_storage_contact_message_default_ip_address() {
return \Drupal::request()->getClientIp();
}
/**
* Implements hook_entity_base_field_info_alter().
*/
function contact_storage_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
if ($entity_type->id() == 'contact_message') {
// Start at min 3 because message default weight is 0.
$i = -3;
foreach (array('name', 'mail', 'subject') as $field_name) {
$fields[$field_name]->setDisplayConfigurable('view', TRUE);
$fields[$field_name]->setDisplayOptions('view', array('weight' => $i));
$i++;
}
// Add a validation constraint to prevent form submission if the limit is
// reached.
$fields['message']->addConstraint('ConstactStorageMaximumSubmissions', []);
}
}
/**
* Implements hook_entity_operation_alter().
*/
function contact_storage_entity_operation_alter(array &$operations, EntityInterface $entity) {
if ($entity->getEntityTypeId() == 'contact_message' && $entity->access('view')) {
$operations['view'] = array(
'title' => t('View'),
'weight' => 0,
'url' => $entity->urlInfo('canonical'),
);
}
if ($entity->getEntityTypeId() == 'contact_form' && $entity->access('update')) {
$operations['clone'] = array(
'title' => t('Clone'),
'weight' => 10,
'url' => $entity->urlInfo('clone-form'),
);
// Provide a link to view messages submitted form the form, if the view
// exists and if the user has access rights to it.
$view = Views::getView('contact_messages');
if ($view && $view->access('page_1')) {
$view->setDisplay('page_1');
$operations['view_messages'] = array(
'title' => t('View messages'),
'url' => $view->getUrl()->setOption('query', ['form' => $entity->id()]),
);
}
}
}
/**
* Implements hook_entity_type_alter().
*/
function contact_storage_entity_type_alter(array &$entity_types) {
/* @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
// Set the controller class for nodes to an alternate implementation of the
// Drupal\Core\Entity\EntityStorageInterface interface.
$entity_types['contact_message']->setStorageClass('\Drupal\Core\Entity\Sql\SqlContentEntityStorage');
$keys = $entity_types['contact_message']->getKeys();
$keys['id'] = 'id';
$keys['label'] = 'subject';
$entity_types['contact_message']->set('entity_keys', $keys);
$entity_types['contact_message']->set('base_table', 'contact_message');
// Add edit and delete forms.
$entity_types['contact_message']->setFormClass('edit', '\Drupal\contact_storage\MessageEditForm');
$entity_types['contact_message']->setFormClass('delete', '\Drupal\Core\Entity\ContentEntityDeleteForm');
// Add clone form for messages.
$entity_types['contact_form']->setFormClass('clone', '\Drupal\contact_storage\Form\ContactFormCloneForm');
// Allow edit/delete links in list builder.
$entity_types['contact_message']->setLinkTemplate('collection', '/admin/structure/contact/messages');
$entity_types['contact_message']->setLinkTemplate('canonical', '/admin/structure/contact/messages/{contact_message}');
$entity_types['contact_message']->setLinkTemplate('edit-form', '/admin/structure/contact/messages/{contact_message}/edit');
$entity_types['contact_message']->setLinkTemplate('delete-form', '/admin/structure/contact/messages/{contact_message}/delete');
// Add clone link for forms.
$entity_types['contact_form']->setLinkTemplate('clone-form', '/admin/structure/contact/manage/{contact_form}/clone');
// Define the entity route provider.
$route_providers = $entity_types['contact_message']->getRouteProviderClasses();
$route_providers['html'] = '\Drupal\contact_storage\ContactRouteProvider';
$entity_types['contact_message']->setHandlerClass('route_provider', $route_providers);
$entity_types['contact_form']->setHandlerClass('route_provider', $route_providers);
// @todo Replace with access control handler when not enough.
$entity_types['contact_message']->set('admin_permission', 'administer contact forms');
// Integrate with Views.
$entity_types['contact_message']->setHandlerClass('views_data', '\Drupal\contact_storage\MessageViewsData');
$entity_types['contact_message']->setListBuilderClass('\Drupal\Core\Entity\EntityListBuilder');
$entity_types['contact_form']->setViewBuilderClass('\Drupal\contact_storage\ContactFormViewBuilder');
// If the body of the message should be sent as HTML.
if (\Drupal::config('contact_storage.settings')->get('send_html')) {
$entity_types['contact_message']->setViewBuilderClass('Drupal\contact_storage\ContactMessageViewBuilder');
}
$keys = $entity_types['contact_form']->getKeys();
$keys['status'] = 'status';
$entity_types['contact_form']->set('entity_keys', $keys);
// Handler classes and templates for the Enable and Disable options.
$entity_types['contact_form']
->setFormClass('disable', ContactFormDisableForm::class)
->setFormClass('enable', ContactFormEnableForm::class)
->setLinkTemplate('enable', '/admin/structure/contact/view/{contact_form}/enable')
->setLinkTemplate('disable', '/admin/structure/contact/view/{contact_form}/disable');
}
/**
* Implements hook_entity_extra_field_info().
*/
function contact_storage_entity_extra_field_info() {
$fields = array();
foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('contact_message')) as $bundle) {
$fields['contact_message'][$bundle]['form']['preview'] = array(
'label' => t('Preview'),
'description' => t('Rendered preview'),
'weight' => 50,
);
}
return $fields;
}
/**
* Implements hook_mail().
*/
function contact_storage_mail($key, &$message, $params) {
$contact_message = $params['contact_message'];
/** @var $sender \Drupal\user\UserInterface */
$sender = $params['sender'];
$language = \Drupal::languageManager()->getLanguage($message['langcode']);
$variables = array(
'@site-name' => \Drupal::config('system.site')->get('name'),
'@subject' => $contact_message->getSubject(),
'@form' => !empty($params['contact_form']) ? $params['contact_form']->label() : NULL,
'@form-url' => \Drupal::url('<current>', [], ['absolute' => TRUE, 'language' => $language]),
'@sender-name' => $sender->getDisplayName(),
);
if ($sender->isAuthenticated()) {
$variables['@sender-url'] = $sender->url('canonical', array('absolute' => TRUE, 'language' => $language));
}
else {
$variables['@sender-url'] = $params['sender']->getEmail();
}
$options = array('langcode' => $language->getId());
switch ($key) {
case 'page_mail':
case 'page_copy':
$message['subject'] .= t('[@form] @subject', $variables, $options);
$message['body'][] = t("@sender-name (@sender-url) sent a message using the contact form at @form-url.", $variables, $options);
$build = entity_view($contact_message, 'mail');
$message['body'][] = \Drupal::service('renderer')->renderPlain($build);
break;
case 'page_autoreply':
$message['subject'] .= t('[@form] @subject', $variables, $options);
$message['body'][] = $params['contact_form']->getReply();
break;
case 'user_mail':
case 'user_copy':
$variables += array(
'@recipient-name' => $params['recipient']->getDisplayName(),
'@recipient-edit-url' => $params['recipient']->url('edit-form', array('absolute' => TRUE, 'language' => $language)),
);
$message['subject'] .= t('[@site-name] @subject', $variables, $options);
$message['body'][] = t('Hello @recipient-name,', $variables, $options);
$message['body'][] = t("@sender-name (@sender-url) has sent you a message via your contact form at @site-name.", $variables, $options);
$message['body'][] = t("If you don't want to receive such emails, you can change your settings at @recipient-edit-url.", $variables, $options);
$build = entity_view($contact_message, 'mail');
$message['body'][] = \Drupal::service('renderer')->renderPlain($build);
break;
}
}
/**
* Implements hook_mail_alter().
*/
function contact_storage_mail_alter(&$message) {
// Check that the message isn't a copy sent to the sender (page_copy).
if (($message['key'] == 'page_mail') && isset($message['params']['contact_message'])) {
$contact_message = $message['params']['contact_message'];
foreach ($contact_message->getFields() as $field) {
if ($field->getFieldDefinition()->getType() === 'contact_storage_options_email') {
// Add recipients to the message from the Option email field.
foreach ($field as $delta => $item) {
$label = $item->value;
// Obtain the email to add to the message, using the label.
$email = $item->getFieldDefinition()->getSetting('allowed_values')[$label]['emails'];
$message['to'] .= ',' . $email;
}
}
}
}
// If enabled, ensure that contact mails are sent as plain text.
// if ($message['module'] === 'contact' && isset($message['params']['contact_message']) && \Drupal::config('contact_storage.settings')->get('send_html')) {
// Enforce that we are sending mails as HTML, and tell Swiftmailer to
// generate a plain text version.
$message['headers']['Content-Type'] = 'text/html';
$message['params']['convert'] = TRUE;
// }
}
/**
* Implements hook_theme().
*/
function contact_storage_theme() {
return array(
'swiftmailer__contact' => array(
'variables' => array(
'message' => array(),
),
),
'contact_storage_disabled_form' => array(
'template' => 'contact-storage-disabled-form',
'variables' => array(
'contact_form' => NULL,
'disabled_form_message' => '',
),
),
);
}
/**
* Prepares variables for contact mail templates.
*
* @param array $variables
* An associative array containing:
* - message: An associative array containing the message array.
* - body: The processed body.
*/
function template_preprocess_swiftmailer__contact(&$variables) {
$variables['subject'] = $variables['message']['subject'];
$variables['body'] = nl2br($variables['message']['body']);
}
/**
* Implements hook_field_formatter_info_alter().
*/
function contact_storage_field_formatter_info_alter(&$info) {
// Let our options_email field type re-use the default list formatter.
$info['list_default']['field_types'][] = 'contact_storage_options_email';
}
/**
* Implements hook_field_widget_info_alter().
*/
function contact_storage_field_widget_info_alter(&$info) {
// Let our options_email field type re-use the default options widget.
$info['options_select']['field_types'][] = 'contact_storage_options_email';
}
/**
* Returns the number of times the current user has submitted the specified
* form.
*
* @param Drupal\contact\ContactFormInterface $contact_form
* The contact_form entity.
*
* @return int
* The number of times the current user has submitted the specified form.
*/
function contact_storage_maximum_submissions_user(ContactFormInterface $contact_form) {
$account = \Drupal::currentUser();
if ($account->isAnonymous()) {
// Anonymous user, limit per submission with the same IP address.
$ip_address = \Drupal::request()->getClientIp();
$query = \Drupal::entityQuery('contact_message')
->condition('contact_form', $contact_form->id())
->condition('ip_address', $ip_address)
->condition('uid', $account->id());
return count($query->execute());
}
else {
// Limit per submission with the same uid.
$query = \Drupal::entityQuery('contact_message')
->condition('contact_form', $contact_form->id())
->condition('uid', $account->id());
return count($query->execute());
}
}
/**
* Implements hook_ENTITY_TYPE_delete() for 'contact_form'.
*/
function contact_storage_contact_form_delete(EntityInterface $entity) {
// Delete all aliases with this contact form as a source.
\Drupal::service('path.alias_storage')->delete(['source' => '/' . $entity->toUrl('canonical')->getInternalPath()]);
}