contact_storage_export-8.x-1.x-dev/src/Form/ContactStorageExportForm.php
src/Form/ContactStorageExportForm.php
<?php
namespace Drupal\contact_storage_export\Form;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\contact_storage_export\ContactStorageExportService;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\contact_storage_export\ContactStorageExport;
use Drupal\contact\Entity\Message;
use Drupal\Core\Messenger\MessengerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The CSV Export general settings form.
*/
class ContactStorageExportForm extends FormBase {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity type bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* The system time.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* The date formatter.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* The contact storage export service.
*
* @var \Drupal\contact_storage_export\ContactStorageExportService
*/
protected $contactStorageExportService;
/**
* The module extension list.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleExtensionList;
/**
* Constructs a ContactStorageExportForm object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityTypeBundleInfo
* The entity type bundle info service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The system time.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter.
* @param \Drupal\contact_storage_export\ContactStorageExportService $contact_storage_export_service
* The contact storage export service.
* @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
* The module extension list.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entityTypeBundleInfo, MessengerInterface $messenger, TimeInterface $time, DateFormatterInterface $date_formatter, ContactStorageExportService $contact_storage_export_service, ModuleExtensionList $module_extension_list) {
$this->entityTypeManager = $entity_type_manager;
$this->entityTypeBundleInfo = $entityTypeBundleInfo;
$this->messenger = $messenger;
$this->time = $time;
$this->dateFormatter = $date_formatter;
$this->contactStorageExportService = $contact_storage_export_service;
$this->moduleExtensionList = $module_extension_list;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('entity_type.bundle.info'),
$container->get('messenger'),
$container->get('datetime.time'),
$container->get('date.formatter'),
$container->get('contact_storage_export.exporter'),
$container->get('extension.list.module')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'contact_storage_export';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$contact_form = $this->getRequest()->get('contact_form');
if ($contact_form) {
return $this->exportForm($contact_form, $form, $form_state);
}
else {
return $this->contactFormSelection($form, $form_state);
}
}
/**
* Form for exporting a particular form.
*
* @param string $contact_form
* The machine name of the contact form.
* @param array $form
* The Drupal form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current form state.
*
* @return array
* The Drupal form.
*/
protected function exportForm($contact_form, array $form, FormStateInterface $form_state) {
$contact_message = $this->getSingleMessage($contact_form);
if (!$contact_message) {
$message = $this->t('There are no messages to be exported for this form.');
$this->messenger->addWarning($message);
}
else {
// Store the requested contact form.
$form['contact_form'] = [
'#type' => 'hidden',
'#value' => $contact_form,
];
// Allow the editor to only export messages since last export.
$form['since_last_export'] = [
'#type' => 'checkbox',
'#title' => $this->t('Only export new messages since the last export'),
];
$last_id = ContactStorageExport::getLastExportId($contact_form);
if (!$this->getSingleMessage($contact_form, $last_id)) {
$form['since_last_export']['#disabled'] = TRUE;
$form['since_last_export']['#description'] = $this->t('This checkbox has been disabled as there are not new messages since your last export.');
}
$form['advanced'] = [
'#type' => 'details',
'#title' => $this->t('Advanced Settings'),
'#open' => FALSE,
];
// Allow the editor to control which columns are to be exported.
$labels = $this->contactStorageExportService->getLabels($contact_message);
unset($labels['uuid']);
$form['advanced']['columns'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Columns to be exported'),
'#required' => TRUE,
'#options' => $labels,
'#default_value' => array_keys($labels),
];
// Allow the editor to override the default file name.
$filename = str_replace('_', '-', $contact_form);
$filename .= '-' . date('Y-m-d--h-i-s');
$filename .= '.csv';
$form['advanced']['filename'] = [
'#type' => 'textfield',
'#title' => $this->t('File name'),
'#required' => TRUE,
'#default_value' => $filename,
'#maxlength' => 240,
];
$form['advanced']['date_format'] = [
'#type' => 'select',
'#title' => $this->t('Created date format'),
'#options' => $this->getDateFormats(),
'#default_value' => 'medium',
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Export'),
'#button_type' => 'primary',
];
// Open form in new window as our batch finish downloads the file.
if (!isset($form['#attributes'])) {
$form['#attributes'] = [];
}
}
return $form;
}
/**
* Form for choosing a form to export.
*
* @param array $form
* The Drupal form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current form state.
*
* @return array
* The Drupal form.
*/
protected function contactFormSelection(array $form, FormStateInterface $form_state) {
if ($bundles = $this->entityTypeBundleInfo->getBundleInfo('contact_message')) {
$options = [];
foreach ($bundles as $key => $bundle) {
$options[$key] = $bundle['label'];
}
$form['contact_form'] = [
'#type' => 'select',
'#title' => $this->t('Contact form'),
'#options' => $options,
'#required' => TRUE,
];
$form['#attributes']['method'] = 'get';
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Select form'),
'#button_type' => 'primary',
];
}
else {
$message = $this->t('You must create a contact form first before you can export.');
$this->messenger->addWarning($message);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$settings = $form_state->getValues();
// Check if there have been messages since the last export if since last
// export setting is checked.
if ($settings['since_last_export']) {
$last_id = ContactStorageExport::getLastExportId($settings['contact_form']);
if (!$this->getSingleMessage($settings['contact_form'], $last_id)) {
$message = $this->t('There have been no new messages since the last export.');
$form_state->setErrorByName('since_last_export', $message);
}
}
// Ensure filename is csv.
$filaname_parts = explode('.', $settings['filename']);
$extension = end($filaname_parts);
if (strtolower($extension) != 'csv') {
$message = $this->t('The filename must end in ".csv"');
$form_state->setErrorByName('filename', $message);
}
// Validate filename for characters not well supported by php.
// @see https://www.drupal.org/node/2472895 from Drupal 7.
// Punctuation characters that are allowed, but not as first/last character.
$punctuation = '-_. ';
$map = [
// Replace (groups of) whitespace characters.
'!\s+!' => ' ',
// Replace multiple dots.
'!\.+!' => '.',
// Remove characters that are not alphanumeric or the allowed punctuation.
"![^0-9A-Za-z$punctuation]!" => '',
];
$sanitised = preg_replace(array_keys($map), array_values($map), $settings['filename']);
$sanitised = trim($sanitised, $punctuation);
if ($sanitised != $settings['filename']) {
$message = $this->t('The filename should not have multiple whitespaces in a row, should not have multiple dots in a row, and should use only alphanumeric charcters.');
$form_state->setErrorByName('filename', $message);
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Path to the batch processing.
$path = $this->moduleExtensionList->getPath('contact_storage_export');
$path .= '/src/ContactStorageExportBatches.php';
// Information to pass to the batch processing.
$settings = $form_state->getValues();
$settings['columns'] = array_filter($settings['columns']);
$batch = [
'title' => $this->t('Exporting'),
'operations' => [
['_contact_storage_export_process_batch', [$settings]],
],
'finished' => '_contact_storage_export_finish_batch',
'file' => $path,
];
batch_set($batch);
}
/**
* Gets a single contact message.
*
* @param string $contact_form
* The machine name of the contact form.
* @param int $since_last_id
* Function getSingleMessage integer since_last_id.
*
* @return bool|\Drupal\contact\Entity\Message
* False or a single contact_message entity.
*/
protected function getSingleMessage($contact_form, $since_last_id = 0) {
$query = $this->entityTypeManager->getStorage('contact_message')->getQuery();
$query->accessCheck(TRUE);
$query->condition('contact_form', $contact_form);
$query->condition('id', $since_last_id, '>');
$query->range(0, 1);
if ($mids = $query->execute()) {
$mid = reset($mids);
if ($message = Message::load($mid)) {
return $message;
}
}
return FALSE;
}
/**
* Returns an array of date formats.
*
* @return array
* key => value array with date_format id => .
*/
protected function getDateFormats() {
$date_formats = DateFormat::loadMultiple();
$formats = [];
$request_time = $this->time->getRequestTime();
foreach ($date_formats as $id => $date_format) {
$formats[$id] = $this->dateFormatter->format($request_time, $id);
}
return $formats;
}
}
