Repository URL to install this package:
|
Version:
2.0.1 ▾
|
<?php
namespace Drupal\custom_forms\Entity;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Annotation\PluralTranslation;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Annotation\ContentEntityType;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\custom_forms\AESEncryption;
use Drupal\state_machine\Plugin\Field\FieldType\StateItemInterface;
use Hashids\Hashids;
/**
* Defines the custom form submission entity class.
*
* @package Drupal\custom_forms\Entity
*
* @ContentEntityType(
* id = "custom_form_submission",
* label = @Translation("Custom Form Submission"),
* label_collection = @Translation("Custom Form Submissions"),
* label_singular = @Translation("Custom Form Submission"),
* label_plural = @Translation("Custom Form Submissions"),
* label_count = @PluralTranslation(
* singular = "@count custom form submission",
* plural = "@count custom form submissions"
* ),
* fieldable = FALSE,
* base_table = "custom_forms_submissions",
* show_revision_ui = FALSE,
* translatable = FALSE,
* entity_keys = {
* "id" = "id",
* "unique_id" = "unique_id",
* },
* )
*/
class CustomFormSubmission extends ContentEntityBase implements CustomFormSubmissionInterface {
use EntityChangedTrait;
use StringTranslationTrait;
/**
* The factory in charge of CRUD operations for custom form items.
*
* @var \Drupal\custom_forms\CustomFormItemFactory
*/
protected $itemFactory;
/**
* The AES encryption functionality.
*
* @var \Drupal\custom_forms\AESEncryption
*/
protected $aes;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* @inheritDoc
*/
public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = []) {
parent::__construct($values, $entity_type, $bundle, $translations);
$this->itemFactory = \Drupal::service('custom_forms.factory.item');
$this->aes = new AESEncryption(Settings::get('custom_forms.aes_key'));
$this->dateFormatter = \Drupal::service('date.formatter');
}
/**
* {@inheritdoc}
*/
public function getData() {
if (!$this->get('data')->isEmpty()) {
$data = $this->get('data')->first()->getValue();
$decoded = base64_decode($data['data'], FALSE);
$decrypted = $this->aes->decrypt($decoded);
$unserialized = unserialize($decrypted, ['allowed_classes' => FALSE]);
return $unserialized;
}
return [];
}
/**
* {@inheritdoc}
*/
public function getMappedData($hide_sensitive = TRUE, &$column_headers = []) {
if (!$this->get('mapped_data')->isEmpty()) {
$data = $this->get('mapped_data')->first()->getValue();
$decoded = base64_decode($data['data'], FALSE);
$decrypted = $this->aes->decrypt($decoded);
$unserialized = unserialize($decrypted, ['allowed_classes' => FALSE]);
$mapped_data = [];
$mapped_data['_id'] = [
'label' => $this->t('Id')->render(),
'value' => $this->id(),
'sensitive' => FALSE,
];
$mapped_data['_unique_id'] = [
'label' => $this->t('Unique id')->render(),
'value' => $this->getUniqueId(),
'sensitive' => FALSE,
];
$form = $this->getForm();
$form_label = 'ID:' . $this->get('form')->target_id;
$form_type_label = '(' . $this->t('Not found')->render() . ')';
if ($form !== NULL) {
$form_label = $form->label();
/** @var \Drupal\custom_forms\Entity\CustomFormType $form_type */
$form_type = CustomFormType::load($this->getForm()->bundle());
if ($form_type !== NULL) {
$form_type_label = $form_type->label();
}
}
$mapped_data['_form'] = [
'label' => $this->t('Form')->render(),
'value' => $form_label,
'sensitive' => FALSE,
];
$mapped_data['_type'] = [
'label' => $this->t('Type')->render(),
'value' => $form_type_label,
'sensitive' => FALSE,
];
$mapped_data += $unserialized;
// Add some additional non-field data to mapped data.
$state_label = $this->getState()->getLabel();
if ($state_label instanceof MarkupInterface) {
$state_label = $state_label->render();
}
$mapped_data['_state'] = [
'label' => $this->t('State')->render(),
'value' => $state_label,
'sensitive' => FALSE,
];
$mapped_data['_created'] = [
'label' => $this->t('Created')->render(),
'value' => $this->getCreatedTime(),
'sensitive' => FALSE,
];
$mapped_data['_changed'] = [
'label' => $this->t('Changed')->render(),
'value' => $this->getChangedTime(),
'sensitive' => FALSE,
];
foreach ($mapped_data as $key => $value) {
// Hide sensitive data.
if ($hide_sensitive && $value['sensitive'] === TRUE) {
$mapped_data[$key]['value'] = $this->t('Hidden')->render();
}
// Add column headers
$column_headers[$key] = $value['label'];
}
return $mapped_data;
}
return [];
}
/**
* {@inheritdoc}
*/
public function setDataArray(array $data) : CustomFormSubmissionInterface {
$serialized = serialize($data);
$encrypted = $this->aes->encrypt($serialized);
$encoded = base64_encode($encrypted);
$this->set('data', ['data' => $encoded]);
return $this;
}
/**
* {@inheritdoc}
*/
public function setMappedDataArray(array $data) : CustomFormSubmissionInterface {
$serialized = serialize($data);
$encrypted = $this->aes->encrypt($serialized);
$encoded = base64_encode($encrypted);
$this->set('mapped_data', ['data' => $encoded]);
return $this;
}
/**
* {@inheritdoc}
*/
public function setFormId($form_id) : CustomFormSubmissionInterface {
$this->set('form', $form_id);
return $this;
}
/**
* {@inheritdoc}
*/
public function setErrors(array $errors) : CustomFormSubmissionInterface {
$this->set('errors', $errors);
return $this;
}
/**
* {@inheritdoc}
*/
public function getUniqueId() : ?string {
return $this->get('unique_id')->value;
}
/**
* {@inheritdoc}
*/
public function getForm() : ?CustomForm {
return $this->get('form')->entity;
}
/**
* {@inheritdoc}
*/
public function getState() : StateItemInterface {
return $this->get('state')->first();
}
/**
* {@inheritdoc}
*/
public function getErrors() : array {
$errors = [];
if (!$this->get('errors')->isEmpty()) {
$errors = $this->get('errors')->first()->getValue();
}
return $errors;
}
/**
* {@inheritdoc}
*/
public function getCreatedTime() : int {
return $this->get('created')->value;
}
/**
* @return \Drupal\Core\Field\FieldItemListInterface|mixed
*/
public function getCreated() {
return $this->get('created');
}
/**
* {@inheritdoc}
*/
public function generateReceiptData() : array {
/** @var \Drupal\custom_forms\Entity\CustomForm $form */
$form = $this->getForm();
$submission_data = $this->getData();
$data = [];
$dateFormatter = \Drupal::service('date.formatter');
$data['submission_date'] = [
'label' => t('Date'),
'value' => $dateFormatter->format($this->getCreatedTime(), 'medium'),
];
$fields = $this->itemFactory->getFormItems($form, TRUE);
$exclude_plugins = [
'submit' // Exclude submit button from appearing on receipt.
];
/** @var \Drupal\custom_forms\CustomFormItem $field */
foreach ($fields as $field) {
if (!empty($submission_data) && $field->getType() === 'field' && !in_array($field->getPluginDefinition()['id'], $exclude_plugins, FALSE)) {
$field_plugin = $field->getPlugin();
$formatted_data = $field_plugin->formatReceiptValue($submission_data);
if (!empty($formatted_data)) {
$data[$field->getMachineName()] = $formatted_data;
}
}
}
return $data;
}
/**
* {@inheritdoc}
*/
public static function loadByUniqueId($id) : ?CustomFormSubmissionInterface {
$query = \Drupal::entityQuery('custom_form_submission');
$query->condition('unique_id', $id);
$query->accessCheck(TRUE);
$result = $query->execute();
// Get the first match.
$id = reset($result);
// Only load the submission if we found a match.
if (!empty($id)) {
return self::load($id);
}
}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
// Set the state to draft if it's not been set
if ($this->get('state')->isEmpty()) {
$this->set('state', 'draft');
}
// Generate a unique ID if it's empty.
if ($this->get('unique_id')->isEmpty()) {
$config = \Drupal::config('custom_forms.settings');
// Generate and save the unique ID.
$hashIds = new Hashids($config->get('submission_salt'), 8);
$unique_id = $hashIds->encode($this->getCreatedTime() . $this->id());
$this->set('unique_id', $unique_id);
}
// Set errors if it's empty.
if ($this->get('errors')->isEmpty()) {
$this->setErrors([]);
}
}
/**
* @inheritDoc
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
$this->setMappedDataArray($this->mapData(FALSE));
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['unique_id'] = BaseFieldDefinition::create('string')
->setLabel(t('Unique id'))
->setDescription(t('The unique id for the submission.'))
->setRequired(TRUE)
->setSetting('max_length', 255)
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE);
$fields['form'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Custom Form'))
->setDescription(t('The custom form which the submission belongs to.'))
->setCardinality(1)
->setRequired(TRUE)
->setSetting('target_type', 'custom_form')
->setSetting('handler', 'default')
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE);
$fields['state'] = BaseFieldDefinition::create('state')
->setLabel(t('State'))
->setDescription(t('The submission state.'))
->setDefaultValue('draft')
->setRequired(TRUE)
->setSetting('max_length', 255)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'state_transition_form',
'weight' => 10,
])
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE)
->setSetting('workflow', 'submission');
$fields['data'] = BaseFieldDefinition::create('map')
->setLabel(t('Data'))
->setDescription(t('A serialized array of submission data.'))
->setDefaultValue([]);
$fields['mapped_data'] = BaseFieldDefinition::create('map')
->setLabel(t('Mapped data'))
->setDescription(t('A serialized array of mapped submission data.'))
->setDefaultValue([]);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time when the submission was created.'));
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setDescription(t('The time when the submission was last edited.'));
$fields['errors'] = BaseFieldDefinition::create('map')
->setLabel(t('Errors'))
->setDescription(t('A serialized array of submission errors.'));
return $fields;
}
/**
* Map the submitted data.
*
* @param bool $hide_sensitive
* Whether to hide sensitive values or not, defaults to TRUE.
*
* @return array
* Returns the mapped data.
*/
private function mapData($hide_sensitive = TRUE) : array {
/** @var \Drupal\custom_forms\Entity\CustomForm $form */
$form = $this->getForm();
$submission_data = $this->getData();
/** @var \Drupal\custom_forms\CustomFormItem[] $items */
$items = $this->itemFactory->getFormItems($form);
// If the form and items failed to load, we return nothing.
// This is because it means the submission was saved outside the flow
// and thus ended in a situation where the associated form or items have
// been deleted.
if ($form === NULL && $items === NULL) {
return [];
}
// Remove internal values from array
unset(
$submission_data['_custom_form_detector'],
$submission_data['_finalize'],
$submission_data['_receipt_page_id'],
$submission_data['_process_file_usage']
);
$mapped_data = [];
foreach ($items as $item) {
if ($item->getType() === 'field') {
try {
/** @var \Drupal\custom_forms\Plugin\CustomForms\FieldMapping\CustomFormsFieldMappingInterface $mapping_plugin */
$mapping_plugin = $this->itemFactory->getItemPlugin('mapping', $item->getMappingId());
// Get all mapping ids and labels so we can loop through them.
$mappings = $mapping_plugin->getMappingIds($item, $mapped_data, FALSE);
// Get the mapped submission data.
$mapped_field = $mapping_plugin->mapValue($submission_data, $mapped_data, $item, $hide_sensitive);
/**
* @var string $mapping_id
* @var \Drupal\Core\StringTranslation\TranslatableMarkup $mapping_label
*/
foreach ($mappings as $mapping_id => $mapping_label) {
if ($mapping_label instanceof MarkupInterface) {
$mapping_label = $mapping_label->render();
}
$mapped_data[$mapping_id] = [
'label' => $mapping_label,
'value' => $mapped_field[$mapping_id],
'sensitive' => $mapping_plugin->isSensitive(),
];
}
} catch (PluginException $e) {
$error_message = t('Failed during data mapping. Message = %message',
[
'%message' => $e->getMessage(),
]
);
\Drupal::logger('Custom Forms')->error($error_message);
}
}
}
return $mapped_data;
}
}