View source
<?php
namespace Drupal\webform\Plugin\Field\FieldWidget;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Element\WebformAjaxElementTrait;
use Drupal\webform\Entity\Webform;
use Drupal\webform\Utility\WebformDateHelper;
use Drupal\webform\WebformInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
trait WebformEntityReferenceWidgetTrait {
use WebformAjaxElementTrait;
protected $elementManager;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->elementManager = $container
->get('plugin.manager.webform.element');
return $instance;
}
public static function defaultSettings() {
return [
'default_data' => TRUE,
'webforms' => NULL,
] + parent::defaultSettings();
}
public function settingsForm(array $form, FormStateInterface $form_state) {
$element = parent::settingsForm($form, $form_state);
$element['default_data'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable default submission data (YAML)'),
'#description' => $this
->t('If checked, site builders will be able to define default submission data (YAML)'),
'#default_value' => $this
->getSetting('default_data'),
];
if ($this
->getSetting('webforms') !== NULL) {
$element['webforms'] = [
'#type' => 'webform_entity_select',
'#title' => $this
->t('Select webform'),
'#description' => $this
->t('If left blank all webforms will be listed in the select menu.'),
'#select2' => TRUE,
'#multiple' => TRUE,
'#target_type' => 'webform',
'#selection_handler' => 'default:webform',
'#default_value' => $this
->getSetting('webforms'),
];
$this->elementManager
->processElement($element['webforms']);
}
return $element;
}
public function settingsSummary() {
$summary = parent::settingsSummary();
$summary[] = $this
->t('Default submission data: @default_data', [
'@default_data' => $this
->getSetting('default_data') ? $this
->t('Yes') : $this
->t('No'),
]);
$webform_ids = $this
->getSetting('webforms');
if ($webform_ids) {
$webforms = Webform::loadMultiple($webform_ids);
$webform_labels = [];
foreach ($webforms as $webform) {
$webform_labels[] = $webform
->label();
}
$summary[] = $this
->t('Webforms: @webforms', [
'@webforms' => implode('; ', $webform_labels),
]);
}
return $summary;
}
protected abstract function getTargetIdElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state);
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
if (!isset($items[$delta]->status)) {
$items[$delta]->status = WebformInterface::STATUS_OPEN;
}
$field_name = $items
->getName();
$field_parents = array_merge($element['#field_parents'], [
$field_name,
$delta,
]);
$field_input_name = array_shift($field_parents) . ('[' . implode('][', $field_parents) . ']');
$target_id_element = $this
->getTargetIdElement($items, $delta, $element, $form, $form_state);
$is_paragraph = $items
->getEntity()
->getEntityTypeId() === 'paragraph';
$element = [
'target_id' => $target_id_element + $element + [
'#weight' => 0,
],
];
$weight = $element['target_id']['#weight'];
$target_id = NULL;
if ($form_state
->isRebuilding()) {
$target_id = $form_state
->getValue(array_merge($element['target_id']['#field_parents'], [
$field_name,
$delta,
'target_id',
]));
}
else {
$target_id = $items[$delta]->target_id;
}
$webform = $target_id ? Webform::load($target_id) : NULL;
$element['settings'] = [
'#type' => 'details',
'#title' => $this
->t('@title settings', [
'@title' => $element['target_id']['#title'],
]),
'#element_validate' => [
[
$this,
'validateOpenClose',
],
],
'#open' => $items[$delta]->target_id ? TRUE : FALSE,
'#weight' => $weight++,
];
$is_webform_closed = $webform && $webform
->isClosed();
if ($is_webform_closed) {
$t_args = [
'%webform' => $webform
->label(),
':href' => $webform
->toUrl('settings-form')
->toString(),
];
if ($webform
->access('update')) {
$message = $this
->t('The %webform webform is <a href=":href">closed</a>. The below status will be ignored.', $t_args);
}
else {
$message = $this
->t('The %webform webform is <strong>closed</strong>. The below status will be ignored.', $t_args);
}
$element['settings']['status_message'] = [
'#type' => 'webform_message',
'#message_type' => 'warning',
'#message_message' => $message,
];
}
else {
$element['settings']['status_message'] = [];
}
$ajax_id = 'webform-entity-reference-' . $field_name . '-' . $delta;
$this
->buildAjaxElementTrigger($ajax_id, $element['target_id']);
$this
->buildAjaxElementUpdate($ajax_id, $element);
$this
->buildAjaxElementWrapper($ajax_id, $element['settings']['status_message']);
$element['settings']['status'] = [
'#type' => 'radios',
'#title' => $this
->t('Status'),
'#description' => $this
->t('The open, closed, or scheduled status applies to only this webform instance.'),
'#options' => [
WebformInterface::STATUS_OPEN => $this
->t('Open'),
WebformInterface::STATUS_CLOSED => $this
->t('Closed'),
WebformInterface::STATUS_SCHEDULED => $this
->t('Scheduled'),
],
'#options_display' => 'side_by_side',
'#default_value' => $items[$delta]->status,
];
$element['settings']['scheduled'] = [
'#type' => 'item',
'#title' => $element['target_id']['#title'],
'#title_display' => 'invisible',
'#input' => FALSE,
'#states' => [
'visible' => [
'input[name="' . $field_input_name . '[settings][status]"]' => [
'value' => WebformInterface::STATUS_SCHEDULED,
],
],
],
];
$element['settings']['scheduled']['open'] = [
'#type' => 'datetime',
'#title' => $this
->t('Open'),
'#default_value' => $items[$delta]->open ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->open)) : NULL,
'#prefix' => '<div class="container-inline form-item">',
'#suffix' => '</div>',
'#help' => FALSE,
'#description' => [
'#type' => 'webform_help',
'#help' => $this
->t('If the open date/time is left blank, this form will immediately be opened.'),
'#help_title' => $this
->t('Open'),
],
];
$element['settings']['scheduled']['close'] = [
'#type' => 'datetime',
'#title' => $this
->t('Close'),
'#default_value' => $items[$delta]->close ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->close)) : NULL,
'#prefix' => '<div class="container-inline form-item">',
'#suffix' => '</div>',
'#help' => FALSE,
'#description' => [
'#type' => 'webform_help',
'#help' => $this
->t('If the close date/time is left blank, this webform will never be closed.'),
'#help_title' => $this
->t('Close'),
],
];
if ($this
->getSetting('default_data')) {
$token_manager = \Drupal::service('webform.token_manager');
$token_types = [
'webform',
'webform_submission',
];
$title = $this
->t('Default submission data (YAML)');
$placeholder = $this
->t("Enter 'name': 'value' pairs…");
$description = [
'content' => [
'#markup' => $this
->t('Enter submission data as name and value pairs as <a href=":href">YAML</a> which will be used to prepopulate the selected webform.', [
':href' => 'https://en.wikipedia.org/wiki/YAML',
]),
'#suffix' => ' ',
],
'token' => $token_manager
->buildTreeLink(),
];
$default_data_example = [];
$default_data_example[] = '# ' . $this
->t('This is an example of a comment.');
$default_data_example[] = "element_key: 'some value'";
$default_data_example[] = '';
$default_data_example[] = '# ' . $this
->t("The below example uses a token to get the current node's title.");
$default_data_example[] = "title: '[webform_submission:node:title:clear]'";
$default_data_example[] = '';
$default_data_example[] = '# ' . $this
->t("Add ':clear' to the end token to return an empty value when the token is missing.");
$default_data_example[] = '# ' . $this
->t('The below example uses a token to get a field value from the current node.');
$default_data_example[] = "full_name: '[webform_submission:node:field_full_name:clear]'";
if ($is_paragraph) {
$token_types[] = 'paragraph';
$default_data_example[] = '';
$default_data_example[] = '# ' . $this
->t('You can also use paragraphs tokens.');
$default_data_example[] = "some_value: '[paragraph:some_value:clear]";
}
$element['settings']['default_data'] = [
'#type' => 'webform_codemirror',
'#mode' => 'yaml',
'#title' => $title,
'#description' => $description,
'#placeholder' => $placeholder,
'#default_value' => $items[$delta]->default_data,
'#webform_element' => TRUE,
'#more_title' => $this
->t('Example'),
'#more' => [
'#theme' => 'webform_codemirror',
'#type' => 'yaml',
'#code' => implode(PHP_EOL, $default_data_example),
],
];
$token_manager
->elementValidate($element['settings']['default_data'], $token_types);
}
else {
$element['settings']['default_data'] = [
'#type' => 'value',
'#value' => $items[$delta]->default_data,
];
}
return $element;
}
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
parent::massageFormValues($values, $form, $form_state);
foreach ($values as &$item) {
$item += $item['settings'];
unset($item['settings']);
$item += [
'target_id' => '',
'default_data' => NULL,
'status' => '',
'open' => '',
'close' => '',
];
if ($item['status'] === WebformInterface::STATUS_SCHEDULED) {
$states = [
'open',
'close',
];
foreach ($states as $state) {
if (!empty($item['scheduled'][$state]) && $item['scheduled'][$state] instanceof DrupalDateTime) {
$item[$state] = WebformDateHelper::formatStorage($item['scheduled'][$state]);
}
else {
$item[$state] = '';
}
}
}
else {
$item['open'] = '';
$item['close'] = '';
}
unset($item['scheduled']);
}
return $values;
}
public function validateOpenClose(array &$element, FormStateInterface $form_state, array &$complete_form) {
$status = $element['status']['#value'];
if ($status === WebformInterface::STATUS_SCHEDULED) {
$open_date = $element['scheduled']['open']['#value']['object'];
$close_date = $element['scheduled']['close']['#value']['object'];
if (empty($open_date) && empty($close_date)) {
$form_state
->setError($element['scheduled']['open'], $this
->t('Please enter an open or close date'));
$form_state
->setError($element['scheduled']['close'], $this
->t('Please enter an open or close date'));
}
if ($open_date instanceof DrupalDateTime && $close_date instanceof DrupalDateTime) {
if ($open_date
->getTimestamp() !== $close_date
->getTimestamp()) {
$interval = $open_date
->diff($close_date);
if ($interval->invert === 1) {
$form_state
->setError($element['scheduled']['open'], $this
->t('The @title close date cannot be before the open date', [
'@title' => $element['#title'],
]));
}
}
}
}
}
}