View source
<?php
namespace Drupal\webform_entity_handler\Plugin\WebformHandler;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Element\WebformSelectOther;
use Drupal\webform\Plugin\WebformElement\WebformCompositeBase;
use Drupal\webform\Plugin\WebformElementManagerInterface;
use Drupal\webform\Plugin\WebformHandlerBase;
use Drupal\webform\WebformSubmissionInterface;
use Drupal\webform\WebformTokenManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class WebformEntityHandler extends WebformHandlerBase {
const DEFAULT_VALUE = '_default';
protected $entityFieldManager;
protected $entityTypeBundleInfo;
protected $entityTypeManager;
protected $webformElementManager;
protected $webformTokenManager;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance
->setEntityFieldManager($container
->get('entity_field.manager'));
$instance
->setEntityTypeBundleInfo($container
->get('entity_type.bundle.info'));
$instance
->setEntityTypeManager($container
->get('entity_type.manager'));
$instance
->setWebformElementManager($container
->get('plugin.manager.webform.element'));
$instance
->setWebformTokenManager($container
->get('webform.token_manager'));
return $instance;
}
public function defaultConfiguration() {
return [
'operation' => self::DEFAULT_VALUE,
'entity_type_id' => NULL,
'entity_values' => [],
'entity_revision' => FALSE,
'states' => [
WebformSubmissionInterface::STATE_COMPLETED,
],
];
}
public function getSummary() {
$configuration = $this
->getConfiguration();
$settings = $configuration['settings'];
$states = [
WebformSubmissionInterface::STATE_DRAFT => $this
->t('Draft Saved'),
WebformSubmissionInterface::STATE_CONVERTED => $this
->t('Converted'),
WebformSubmissionInterface::STATE_COMPLETED => $this
->t('Completed'),
WebformSubmissionInterface::STATE_UPDATED => $this
->t('Updated'),
WebformSubmissionInterface::STATE_LOCKED => $this
->t('Locked'),
];
$settings['states'] = array_intersect_key($states, array_combine($settings['states'], $settings['states']));
return [
'#settings' => $settings,
] + parent::getSummary();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$this
->applyFormStateToConfiguration($form_state);
$webform_elements = $this
->getElements();
$form['entity_settings'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Entity settings'),
'#collapsible' => FALSE,
];
$form['entity_settings']['operation'] = [
'#type' => 'webform_select_other',
'#title' => $this
->t('Entity operation'),
'#description' => $this
->t('If the entity ID is empty a new entity will be created and then updated with the new entity ID.'),
'#options' => [
self::DEFAULT_VALUE => $this
->t('Create a new entity'),
$this
->t('or update entity ID stored in the following submission element:')
->__toString() => $webform_elements,
WebformSelectOther::OTHER_OPTION => $this
->t('Update custom entity ID…'),
],
'#empty_option' => $this
->t('- Select -'),
'#required' => TRUE,
'#default_value' => $this->configuration['operation'],
'#parents' => [
'settings',
'operation',
],
];
$form['entity_settings']['entity_type_id'] = [
'#type' => 'select',
'#title' => $this
->t('Entity type'),
'#options' => $this
->getEntityTypes(),
'#empty_option' => $this
->t('- Select -'),
'#required' => TRUE,
'#default_value' => $this->configuration['entity_type_id'],
'#ajax' => [
'callback' => [
get_called_class(),
'updateEntityFields',
],
'wrapper' => 'webform-entity-handler--entity-values',
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Loading fields...'),
],
],
'#parents' => [
'settings',
'entity_type_id',
],
];
$form['entity_settings']['entity_values'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Entity values'),
'#attributes' => [
'id' => 'webform-entity-handler--entity-values',
],
'#collapsible' => FALSE,
];
if (!empty($this->configuration['entity_type_id'])) {
$form['entity_settings']['entity_values'] += $this
->getEntityFieldsForm($this->configuration['entity_type_id']);
}
$form['entity_settings']['entity_revision'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Create new revision'),
'#default_value' => $this->configuration['entity_revision'],
'#access' => FALSE,
'#parents' => [
'settings',
'entity_revision',
],
];
if (!empty($this->configuration['entity_type_id'])) {
[
$type,
] = explode(':', $this->configuration['entity_type_id']);
$form['entity_settings']['entity_revision']['#access'] = $this->entityTypeManager
->getDefinition($type)
->isRevisionable();
}
$form['token_tree_link'] = $this->webformTokenManager
->buildTreeLink();
$results_disabled = $this
->getWebform()
->getSetting('results_disabled');
$form['additional'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Additional settings'),
];
$form['additional']['states'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Execute'),
'#options' => [
WebformSubmissionInterface::STATE_DRAFT => $this
->t('…when <b>draft</b> is saved.'),
WebformSubmissionInterface::STATE_CONVERTED => $this
->t('…when anonymous submission is <b>converted</b> to authenticated.'),
WebformSubmissionInterface::STATE_COMPLETED => $this
->t('…when submission is <b>completed</b>.'),
WebformSubmissionInterface::STATE_UPDATED => $this
->t('…when submission is <b>updated</b>.'),
WebformSubmissionInterface::STATE_DELETED => $this
->t('…when submission is <b>deleted</b>.'),
],
'#parents' => [
'settings',
'states',
],
'#access' => $results_disabled ? FALSE : TRUE,
'#default_value' => $results_disabled ? [
WebformSubmissionInterface::STATE_COMPLETED,
] : $this->configuration['states'],
];
if (method_exists($this, 'elementTokenValidate')) {
$this
->elementTokenValidate($form);
}
return $this
->setSettingsParents($form);
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
if ($form_state
->hasAnyErrors()) {
return;
}
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$this
->applyFormStateToConfiguration($form_state);
$this->configuration['states'] = array_values(array_filter($this->configuration['states']));
$this->configuration['entity_values'] = array_map('array_filter', $this->configuration['entity_values']);
$this->configuration['entity_values'] = array_filter($this->configuration['entity_values']);
}
public static function updateEntityFields(array $form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$array_parents = array_slice($triggering_element['#array_parents'], 0, -1);
$element = NestedArray::getValue($form, $array_parents);
$response = new AjaxResponse();
$response
->addCommand(new ReplaceCommand('#webform-entity-handler--entity-values', $element['entity_values']));
return $response;
}
public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE) {
$state = $webform_submission
->getWebform()
->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission
->getState();
if (in_array($state, $this->configuration['states'])) {
$data = $this->configuration['entity_values'];
$submission_data = $webform_submission
->getData();
array_walk_recursive($data, function (&$value) use ($webform_submission, $submission_data) {
if (strpos($value, 'input:') !== FALSE) {
[
,
$element_key,
] = explode(':', $value);
$element_key = explode('|', $element_key);
$value = NestedArray::getValue($submission_data, $element_key);
}
elseif ($value === '_null_') {
$value = NULL;
}
$value = $this->tokenManager
->replace($value, $webform_submission, [], [
'clear' => TRUE,
]);
});
[
$type,
$bundle,
] = explode(':', $this->configuration['entity_type_id']);
if ($this->entityTypeManager
->getDefinition($type)
->hasKey('bundle')) {
$data[$this->entityTypeManager
->getDefinition($type)
->getKey('bundle')] = $bundle;
}
try {
$entity_id = FALSE;
if ($this->configuration['operation'] != self::DEFAULT_VALUE) {
if (strpos($this->configuration['operation'], 'input:') !== FALSE) {
[
,
$element_key,
] = explode(':', $this->configuration['operation']);
$element_key = explode('|', $element_key);
$entity_id = NestedArray::getValue($submission_data, $element_key);
}
else {
$entity_id = $this->configuration['operation'];
}
$entity_id = $this->webformTokenManager
->replace($entity_id, $webform_submission);
}
if (!empty($entity_id)) {
if (($entity = $this->entityTypeManager
->getStorage($type)
->load($entity_id)) !== NULL) {
if ($this->entityTypeManager
->getDefinition($type)
->hasKey('bundle') && $bundle != $entity
->bundle()) {
$previous_entity = clone $entity;
$entity
->delete();
unset($entity);
foreach (array_keys($data) as $field_name) {
if (empty($data[$field_name]) && $previous_entity
->hasField($field_name) && !$previous_entity
->get($field_name)
->isEmpty()) {
$data[$field_name] = $previous_entity
->get($field_name)
->getValue();
}
}
$data['id'] = $previous_entity
->id();
$data['uuid'] = $previous_entity
->uuid();
}
else {
foreach ($data as $field => $value) {
$append = !empty($value['webform_entity_handler_append']);
if (isset($value['webform_entity_handler_append'])) {
unset($value['webform_entity_handler_append']);
}
if ($append && !$entity
->get($field)
->isEmpty()) {
$entity
->get($field)
->appendItem($value);
}
else {
$entity
->set($field, $value);
}
}
}
}
}
if (empty($entity)) {
$entity = $this->entityTypeManager
->getStorage($type)
->create($data);
}
if ($this->entityTypeManager
->getDefinition($type)
->isRevisionable()) {
$entity
->setNewRevision($this->configuration['entity_revision']);
}
if ($entity
->save() == SAVED_NEW) {
$message = '@type %title has been created.';
}
else {
$message = '@type %title has been updated.';
}
$context = [
'@type' => $entity
->getEntityType()
->getLabel(),
'%title' => $entity
->label(),
];
if ($entity
->hasLinkTemplate('canonical')) {
$context += [
'link' => $entity
->toLink($this
->t('View'))
->toString(),
];
}
if ($webform_submission
->getWebform()
->hasSubmissionLog()) {
$context += [
'link' => $webform_submission
->id() ? $webform_submission
->toLink($this
->t('View'))
->toString() : NULL,
'webform_submission' => $webform_submission,
'handler_id' => $this
->getHandlerId(),
'operation' => 'sent email',
];
$this
->getLogger('webform_submission')
->notice($message, $context);
}
else {
$context += [
'link' => $this
->getWebform()
->toLink($this
->t('Edit'), 'handlers')
->toString(),
];
$this
->getLogger('webform_entity_handler')
->notice($message, $context);
}
if ($entity && $this->configuration['operation'] != self::DEFAULT_VALUE && strpos($this->configuration['operation'], 'input:') !== FALSE) {
[
,
$element_key,
] = explode(':', $this->configuration['operation']);
$element_key = explode('|', $element_key);
$webform_submission
->setElementData(end($element_key), $entity
->id());
$webform_submission
->resave();
}
} catch (\Exception $exception) {
watchdog_exception('webform_entity_handler', $exception);
$this
->messenger()
->addError($this
->t('There was a problem processing your request. Please, try again.'));
}
}
}
protected function getElements() {
$elements_options =& drupal_static(__FUNCTION__);
if (is_null($elements_options)) {
$elements_options = [];
foreach ($this
->getWebform()
->getElementsInitializedAndFlattened() as $element) {
try {
$element_plugin = $this->webformElementManager
->getElementInstance($element);
if (!$element_plugin instanceof WebformCompositeBase) {
$t_args = [
'@title' => $element['#title'],
'@type' => $element_plugin
->getPluginLabel(),
];
$elements_options['input:' . $element['#webform_key']] = $this
->t('@title [@type]', $t_args);
}
else {
$element_group = $element_plugin
->getElementSelectorOptions($element);
foreach ($element_group as $group_key => $group) {
foreach ($group as $sub_element_key => $sub_element) {
if (preg_match('/^:input\\[name=\\"(.*?)\\"]$/', $sub_element_key, $match) == TRUE) {
$sub_element_key = array_map(function ($item) {
return rtrim($item, ']');
}, explode('[', $match[1]));
if ($element['#webform_composite_elements'][end($sub_element_key)]['#type'] == 'managed_file') {
array_shift($sub_element_key);
}
$elements_options[$group_key]['input:' . implode('|', $sub_element_key)] = $sub_element;
}
}
}
}
} catch (\Exception $exception) {
}
}
}
return $elements_options;
}
protected function getEntityTypes() {
$types = [];
foreach ($this->entityTypeManager
->getDefinitions() as $entity_id => $entity_type) {
if ($entity_type instanceof ContentEntityTypeInterface) {
if ($entity_type
->getBundleEntityType() !== NULL) {
foreach ($this->entityTypeBundleInfo
->getBundleInfo($entity_id) as $bundle_id => $bundle_type) {
$types[$entity_type
->getLabel()
->__toString()][$entity_id . ':' . $bundle_id] = $bundle_type['label'];
}
}
else {
$types[$entity_type
->getLabel()
->__toString()][$entity_id . ':' . $entity_id] = $entity_type
->getLabel();
}
}
}
$type_keys = array_keys($types);
array_multisort($type_keys, SORT_NATURAL, $types);
return $types;
}
protected function getEntityFieldsForm($entity_type_bundle) {
$form = [];
[
$type,
$bundle,
] = explode(':', $entity_type_bundle);
$fields = $this->entityFieldManager
->getFieldDefinitions($type, $bundle);
foreach ($fields as $field_name => $field) {
$base_field = BaseFieldDefinition::create($field
->getType());
$field_properties = method_exists($field, 'getPropertyDefinitions') ? $field
->getPropertyDefinitions() : $base_field
->getPropertyDefinitions();
if (empty($field_properties)) {
$field_properties = $base_field
->getPropertyDefinitions();
}
$field_schema = method_exists($field, 'getSchema') ? $field
->getSchema() : $base_field
->getSchema();
if (!empty($field_schema['columns'])) {
$field_properties = array_intersect_key($field_properties, $field_schema['columns']);
}
if (!empty($field_properties)) {
$form[$field_name] = [
'#type' => 'details',
'#title' => $this
->t('@label (Property: @name - Type: @type)', [
'@label' => $field
->getLabel(),
'@name' => $field_name,
'@type' => $field
->getType(),
]),
'#description' => $field
->getDescription(),
'#open' => FALSE,
'#required' => $field
->isRequired(),
];
foreach ($field_properties as $property_name => $property) {
$form[$field_name][$property_name] = [
'#type' => 'webform_select_other',
'#title' => $this
->t('Column: @name - Type: @type', [
'@name' => $property
->getLabel(),
'@type' => $property
->getDataType(),
]),
'#description' => $property
->getDescription(),
'#options' => [
'_null_' => $this
->t('Null'),
] + $this
->getElements() + [
WebformSelectOther::OTHER_OPTION => $this
->t('Custom value…'),
],
'#default_value' => $this->configuration['entity_values'][$field_name][$property_name] ?? NULL,
'#empty_value' => NULL,
'#empty_option' => $this
->t('- Select -'),
'#parents' => [
'settings',
'entity_values',
$field_name,
$property_name,
],
'#other__type' => 'textfield',
];
}
$form[$field_name]['webform_entity_handler_append'] = [
'#type' => 'checkbox',
'#title' => $this
->t('If checked, the value will be appended rather than overridden. Only apply updating an entity.'),
'#default_value' => $this->configuration['entity_values'][$field_name]['webform_entity_handler_append'] ?? NULL,
'#parents' => [
'settings',
'entity_values',
$field_name,
'webform_entity_handler_append',
],
'#access' => $field
->getFieldStorageDefinition()
->getCardinality() != 1,
];
}
}
try {
$entity_id_key = $this->entityTypeManager
->getDefinition($type)
->getKey('id');
unset($form[$entity_id_key]);
if ($this->entityTypeManager
->getDefinition($type)
->hasKey('bundle')) {
unset($form[$this->entityTypeManager
->getDefinition($type)
->getKey('bundle')]);
}
} catch (\Exception $exception) {
}
return $form;
}
public function setEntityFieldManager(EntityFieldManager $entity_field_manager) {
$this->entityFieldManager = $entity_field_manager;
return $this;
}
public function setEntityTypeBundleInfo(EntityTypeBundleInfoInterface $entity_type_bundle_info) {
$this->entityTypeBundleInfo = $entity_type_bundle_info;
return $this;
}
protected function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
return $this;
}
protected function setWebformElementManager(WebformElementManagerInterface $webform_element_manager) {
$this->webformElementManager = $webform_element_manager;
return $this;
}
protected function setWebformTokenManager(WebformTokenManagerInterface $webform_token_manager) {
$this->webformTokenManager = $webform_token_manager;
return $this;
}
}