View source
<?php
namespace Drupal\webform;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\webform\Cache\WebformBubbleableMetadata;
use Drupal\webform\Entity\WebformSubmission;
use Drupal\webform\Form\WebformDialogFormTrait;
use Drupal\webform\Plugin\WebformElement\Hidden;
use Drupal\webform\Plugin\WebformElement\OptionsBase;
use Drupal\webform\Plugin\WebformElement\WebformCompositeBase;
use Drupal\webform\Plugin\WebformElementEntityReferenceInterface;
use Drupal\webform\Plugin\WebformElementOtherInterface;
use Drupal\webform\Plugin\WebformElementWizardPageInterface;
use Drupal\webform\Plugin\WebformHandlerInterface;
use Drupal\webform\Plugin\WebformSourceEntityManager;
use Drupal\webform\Utility\WebformArrayHelper;
use Drupal\webform\Utility\WebformDialogHelper;
use Drupal\webform\Utility\WebformElementHelper;
use Drupal\webform\Utility\WebformOptionsHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class WebformSubmissionForm extends ContentEntityForm {
use WebformDialogFormTrait;
protected $configFactory;
protected $renderer;
protected $formBuilder;
protected $killSwitch;
protected $aliasManager;
protected $pathValidator;
protected $entityFieldManager;
protected $selectionManager;
protected $elementManager;
protected $requestHandler;
protected $thirdPartySettingsManager;
protected $messageManager;
protected $tokenManager;
protected $conditionsValidator;
protected $webformEntityReferenceManager;
protected $generate;
protected $entity;
protected $sourceEntity;
protected $statesPrefix;
protected $originalData;
protected $bubbleableMetadata;
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->configFactory = $container
->get('config.factory');
$instance->renderer = $container
->get('renderer');
$instance->formBuilder = $container
->get('form_builder');
$instance->killSwitch = $container
->get('page_cache_kill_switch');
$instance->aliasManager = $container
->get('path_alias.manager');
$instance->pathValidator = $container
->get('path.validator');
$instance->selectionManager = $container
->get('plugin.manager.entity_reference_selection');
$instance->entityFieldManager = $container
->get('entity_field.manager');
$instance->requestHandler = $container
->get('webform.request');
$instance->elementManager = $container
->get('plugin.manager.webform.element');
$instance->thirdPartySettingsManager = $container
->get('webform.third_party_settings_manager');
$instance->messageManager = $container
->get('webform.message_manager');
$instance->tokenManager = $container
->get('webform.token_manager');
$instance->conditionsValidator = $container
->get('webform_submission.conditions_validator');
$instance->webformEntityReferenceManager = $container
->get('webform.entity_reference_manager');
$instance->generate = $container
->get('webform_submission.generate');
return $instance;
}
public function getBaseFormId() {
$base_form_id = $this->entity
->getEntityTypeId();
$base_form_id .= '_' . $this->entity
->bundle();
return $base_form_id . '_form';
}
public function getFormId() {
$form_id = $this->entity
->getEntityTypeId();
$form_id .= '_' . $this->entity
->bundle();
if ($source_entity = $this->entity
->getSourceEntity()) {
$form_id .= '_' . $source_entity
->getEntityTypeId() . '_' . $source_entity
->id();
}
if ($this->operation !== 'default') {
$form_id .= '_' . $this->operation;
}
return $form_id . '_form';
}
protected function getWrapperId() {
$form_id = $this->entity
->getEntityTypeId();
$form_id .= '_' . $this->entity
->bundle();
if ($source_entity = $this->entity
->getSourceEntity()) {
$form_id .= '_' . $source_entity
->getEntityTypeId() . '_' . $source_entity
->id();
}
$form_id .= '_form';
return Html::getId($form_id . '-ajax');
}
protected function init(FormStateInterface $form_state) {
parent::init($form_state);
$this
->getWebform()
->invokeHandlers('prepareForm', $this->entity, $this->operation, $form_state);
}
public function setEntity(EntityInterface $entity) {
$this->bubbleableMetadata = new WebformBubbleableMetadata();
$webform = $entity
->getWebform();
if (!isset($this->originalData)) {
$this->originalData = $entity
->getRawData();
}
$data = $entity
->getRawData();
if ($this->operation === 'add' && $this
->getRequest()->query
->get('_webform_test') === $webform
->id() && $webform
->access('test')) {
$this->operation = 'test';
}
if ($this->operation === 'test' && $webform
->access('test')) {
$webform
->applyVariants($entity);
$data = $webform
->getVariantsData($entity) + $this->generate
->getData($webform) + $data;
}
$source_entity = $entity
->getSourceEntity(TRUE) ?: $this->requestHandler
->getCurrentSourceEntity([
'webform',
]);
if ($source_entity === $entity) {
$source_entity = $this->requestHandler
->getCurrentSourceEntity([
'webform',
'webform_submission',
]);
}
if ($source_entity && $source_entity
->getEntityTypeId() === 'paragraph') {
$data = $this->tokenManager
->replace($data, $source_entity, [], [
'suffixes' => [
'clear' => FALSE,
],
], $this->bubbleableMetadata);
$source_entity = WebformSourceEntityManager::getMainSourceEntity($source_entity);
}
$this->sourceEntity = $source_entity;
$account = $this
->currentUser();
if (!in_array($this->operation, [
'edit',
'edit_all',
'test',
])) {
$token = $this
->getRequest()->query
->get('token');
$webform_submission_token = $this
->getStorage()
->loadFromToken($token, $webform, $source_entity);
if ($webform_submission_token) {
$entity = $webform_submission_token;
$data = $entity
->getRawData();
$this->operation = 'edit';
}
elseif ($webform
->getSetting('draft') !== WebformInterface::DRAFT_NONE) {
if ($webform
->getSetting('draft_multiple')) {
$webform_submission_token = $this
->getStorage()
->loadFromToken($token, $webform, $source_entity, $account);
if ($webform_submission_token && $webform_submission_token
->isDraft()) {
$entity = $webform_submission_token;
$data = $entity
->getRawData();
}
elseif (isset($_POST['webform_submission_token'])) {
$webform_submission_token = $this
->getStorage()
->loadFromToken($_POST['webform_submission_token'], $webform, $source_entity, $account);
if ($webform_submission_token && $webform_submission_token
->isDraft()) {
$entity = $webform_submission_token;
$data = $entity
->getRawData();
}
}
}
elseif ($webform_submission_draft = $this
->getStorage()
->loadDraft($webform, $source_entity, $account)) {
$entity = $webform_submission_draft;
$data = $entity
->getRawData();
}
}
}
$this->entity = $entity;
if ($entity
->isNew()) {
$last_submission = NULL;
if ($webform
->getSetting('limit_total_unique')) {
if (!$webform
->access('submission_view_any') || !$webform
->access('submission_update_any')) {
throw new AccessDeniedHttpException();
}
$last_submission = $this
->getStorage()
->getLastSubmission($webform, $source_entity, NULL, [
'in_draft' => FALSE,
]);
}
elseif ($webform
->getSetting('limit_user_unique')) {
if (!$account
->isAuthenticated()) {
throw new AccessDeniedHttpException();
}
if (!$webform
->access('submission_view_own') || !$webform
->access('submission_update_own')) {
throw new AccessDeniedHttpException();
}
$last_submission = $this
->getStorage()
->getLastSubmission($webform, $source_entity, $account, [
'in_draft' => FALSE,
]);
}
if ($webform
->isClosed() && !$webform
->access('submission_update_any')) {
$last_submission = NULL;
}
if ($last_submission) {
$entity = $last_submission;
$data = $entity
->getRawData();
$this->operation = 'edit';
}
}
if ($this->operation === 'add' && $entity
->isNew() && $webform
->getSetting('autofill')) {
if ($last_submission = $this
->getStorage()
->getLastSubmission($webform, $source_entity, $account, [
'in_draft' => FALSE,
'access_check' => FALSE,
])) {
$excluded_elements = $webform
->getSetting('autofill_excluded_elements') ?: [];
$last_submission_data = array_diff_key($last_submission
->getRawData(), $excluded_elements);
$data = $last_submission_data + $data;
}
}
$default_data = $webform
->getElementsDefaultData();
$default_data = $this->tokenManager
->replace($default_data, $entity, [], [], $this->bubbleableMetadata);
$data += $default_data;
$entity
->setData($data);
$this
->overrideSettings($entity);
$webform
->setOperation($this->operation);
return parent::setEntity($entity);
}
public function buildEntity(array $form, FormStateInterface $form_state) {
$entity = parent::buildEntity($form, $form_state);
$this
->overrideSettings($entity);
return $entity;
}
protected function overrideSettings(WebformSubmissionInterface $webform_submission) {
$webform = $webform_submission
->getWebform();
$webform
->invokeHandlers('overrideSettings', $webform_submission);
if ($this
->getRequest()->query
->get('_webform_dialog') && !$webform
->getSetting('ajax', TRUE)) {
$webform
->setSettingOverride('ajax', TRUE);
}
if ($this
->isSharePage() && !$webform
->getSetting('ajax', TRUE)) {
$webform
->setSettingOverride('ajax', TRUE);
}
$source_entity = $webform_submission
->getSourceEntity();
if ($webform
->isOpen() && $source_entity && $source_entity instanceof FieldableEntityInterface) {
foreach ($source_entity
->getFieldDefinitions() as $fieldName => $fieldDefinition) {
if ($fieldDefinition
->getType() === 'webform') {
$item = $source_entity
->get($fieldName);
if ($item->target_id === $webform
->id()) {
$webform
->setOverride()
->set('open', $item->open)
->set('close', $item->close)
->setStatus($item->status);
}
}
}
}
}
public function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
$webform_submission = $entity;
$webform = $webform_submission
->getWebform();
$element_values = array_intersect_key($form_state
->getValues(), $webform
->getElementsInitializedFlattenedAndHasValue());
$webform_submission
->setData($element_values + $webform_submission
->getData());
$base_field_definitions = $this->entityFieldManager
->getBaseFieldDefinitions($entity
->getEntityTypeId());
$all_fields = $webform_submission
->getFields(FALSE);
$bundle_fields = array_diff_key($all_fields, $base_field_definitions);
$field_values = array_intersect_key($form_state
->getValues(), $bundle_fields);
foreach ($field_values as $name => $field_value) {
$webform_submission
->set($name, $field_value);
}
if ($current_page = $this
->getCurrentPage($form, $form_state)) {
$entity
->setCurrentPage($current_page);
}
$in_draft = $form_state
->get('in_draft');
if ($in_draft !== NULL) {
$entity
->set('in_draft', $in_draft);
}
}
public function buildForm(array $form, FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
$webform = $this
->getWebform();
if ($webform
->getSetting('draft_multiple') && ($webform_submission
->isNew() || $webform_submission
->isDraft())) {
$form['webform_submission_token'] = [
'#type' => 'hidden',
'#value' => $webform_submission
->getToken(),
];
}
if (!$form_state
->isRebuilding()) {
$data = $webform_submission
->getData();
$this
->prepopulateData($data);
$webform_submission
->setData($data);
}
$webform
->applyVariants($webform_submission);
$this
->addCacheableDependency($form);
$this->renderer
->addCacheableDependency($form, $webform);
if ($webform
->isScheduled() && $this
->currentUser()
->isAnonymous() && $this->moduleHandler
->moduleExists('page_cache')) {
$this->killSwitch
->trigger();
}
$this
->displayMessages($form, $form_state);
$form = parent::buildForm($form, $form_state);
if ($this
->isAjax()) {
$form['#webform_ajax_scroll_top'] = $this
->getWebformSetting('ajax_scroll_top', '');
}
if (isset($form['elements']) && is_array($form['elements'])) {
$elements = $form['elements'];
$this
->alterElementsForm($elements, $form, $form_state);
}
$ajax_settings = [
'effect' => $this
->getWebformSetting('ajax_effect'),
'speed' => (int) $this
->getWebformSetting('ajax_speed'),
'progress' => [
'type' => $this
->getWebformSetting('ajax_progress_type'),
'message' => '',
],
];
$form = $this
->buildAjaxForm($form, $form_state, $ajax_settings);
$this
->getWebform()
->invokeHandlers('alterForm', $form, $form_state, $webform_submission);
$form_id = $this
->getFormId();
$this->thirdPartySettingsManager
->alter('webform_submission_form', $form, $form_state, $form_id);
$this->conditionsValidator
->buildForm($form, $form_state);
$this->bubbleableMetadata
->appendTo($form);
return $form;
}
public function form(array $form, FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
$source_entity = $webform_submission
->getSourceEntity();
$webform = $this
->getWebform();
$form['#webform_id'] = $webform
->id();
$track = $this
->getWebform()
->getSetting('wizard_track');
if ($track && $this
->getRequest()
->isMethod('POST')) {
$current_page = $this
->getCurrentPage($form, $form_state);
if ($track === 'index') {
$pages = $this
->getWebform()
->getPages($this->operation);
$track_pages = array_flip(array_keys($pages));
$form['#attributes']['data-webform-wizard-current-page'] = $track_pages[$current_page] + 1;
}
else {
$form['#attributes']['data-webform-wizard-current-page'] = $current_page;
}
}
$form['#theme'] = [
'webform_submission_form',
];
$webform_id = Html::cleanCssIdentifier($webform
->id());
$operation = $this->operation;
$class = [];
$class[] = "webform-submission-form";
$class[] = "webform-submission-{$operation}-form";
$class[] = "webform-submission-{$webform_id}-form";
$class[] = "webform-submission-{$webform_id}-{$operation}-form";
if ($source_entity) {
$source_entity_type = $source_entity
->getEntityTypeId();
$source_entity_id = $source_entity
->id();
$class[] = "webform-submission-{$webform_id}-{$source_entity_type}-{$source_entity_id}-form";
$class[] = "webform-submission-{$webform_id}-{$source_entity_type}-{$source_entity_id}-{$operation}-form";
}
array_walk($class, [
'\\Drupal\\Component\\Utility\\Html',
'getClass',
]);
$form['#attributes']['class'] = $class;
$this->statesPrefix = '.' . end($class);
if ($custom_form = $this
->getCustomForm($form, $form_state)) {
$custom_form['#custom_form'] = TRUE;
return $custom_form;
}
$form = parent::form($form, $form_state);
if (!$webform_submission
->isNew() && !$webform_submission
->isDraft()) {
$form['navigation'] = [
'#type' => 'webform_submission_navigation',
'#webform_submission' => $webform_submission,
'#weight' => -20,
];
$form['information'] = [
'#type' => 'webform_submission_information',
'#webform_submission' => $webform_submission,
'#source_entity' => $this->sourceEntity,
'#weight' => -19,
];
}
if ($webform_confirmation_modal = $form_state
->get('webform_confirmation_modal')) {
$form['webform_confirmation_modal'] = [
'#type' => 'webform_message',
'#message_type' => 'status',
'#message_message' => [
'title' => [
'#markup' => $webform_confirmation_modal['title'],
'#prefix' => '<b class="webform-confirmation-modal--title">',
'#suffix' => '</b><br/>',
],
'content' => [
'content' => $webform_confirmation_modal['content'],
'#prefix' => '<div class="webform-confirmation-modal--content">',
'#suffix' => '</div>',
],
],
'#attributes' => [
'class' => [
'js-hide',
'webform-confirmation-modal',
'js-webform-confirmation-modal',
],
],
'#weight' => -1000,
'#attached' => [
'library' => [
'webform/webform.confirmation.modal',
],
],
'#element_validate' => [
'::removeConfirmationModal',
],
];
}
$data = $webform_submission
->getData();
$elements = $webform_submission
->getWebform()
->getElementsInitialized();
$this
->populateElements($elements, $data);
$this
->prepareElements($elements, $form, $form_state);
$pages = $webform
->getPages($this->operation);
if ($pages && $operation !== 'edit_all') {
$current_page = $this
->getCurrentPage($form, $form_state);
$form['pages'] = $this
->pagesElement($form, $form_state);
$display_wizard_progress = $this
->getWebformSetting('wizard_progress_bar') || $this
->getWebformSetting('wizard_progress_pages') || $this
->getWebformSetting('wizard_progress_percentage');
if ($current_page && $display_wizard_progress) {
$form['progress'] = [
'#theme' => 'webform_progress',
'#webform' => $this
->getWebform(),
'#webform_submission' => $webform_submission,
'#current_page' => $current_page,
'#operation' => $this->operation,
'#weight' => -20,
];
}
}
$current_page = $this
->getCurrentPage($form, $form_state);
if ($current_page !== WebformInterface::PAGE_PREVIEW && $this
->getWebformSetting('form_required') && $webform
->hasRequired()) {
$form['required'] = [
'#theme' => 'webform_required',
'#label' => $this
->getWebformSetting('form_required_label'),
];
}
$form['elements'] = $elements;
$this
->displayCurrentPage($form, $form_state);
$this
->setFormPropertiesFromElements($form, $elements);
$this
->attachLibraries($form, $form_state);
$this
->attachBehaviors($form, $form_state);
$form['#after_build'][] = '::afterBuild';
return $form;
}
protected function getCustomForm(array &$form, FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
$webform = $this
->getWebform();
if (!$webform_submission
->getWebform()
->getElementsInitialized()) {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_EXCEPTION_MESSAGE, 'warning');
}
if ($webform_submission
->isLocked()) {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::SUBMISSION_LOCKED_MESSAGE, 'warning');
}
if ($webform
->getSetting('form_prepopulate_source_entity')) {
if ($webform
->getSetting('form_prepopulate_source_entity_required') && empty($this
->getSourceEntity())) {
$this
->getMessageManager()
->log(WebformMessageManagerInterface::PREPOPULATE_SOURCE_ENTITY_REQUIRED, 'notice');
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::PREPOPULATE_SOURCE_ENTITY_REQUIRED, 'warning');
}
$source_entity_type = $webform
->getSetting('form_prepopulate_source_entity_type');
if ($source_entity_type && $this
->getSourceEntity() && $source_entity_type !== $this
->getSourceEntity()
->getEntityTypeId()) {
$this
->getMessageManager()
->log(WebformMessageManagerInterface::PREPOPULATE_SOURCE_ENTITY_TYPE, 'notice');
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::PREPOPULATE_SOURCE_ENTITY_TYPE, 'warning');
}
}
if ($form_state
->get('current_page') === WebformInterface::PAGE_CONFIRMATION) {
$form['confirmation'] = [
'#theme' => 'webform_confirmation',
'#webform' => $webform,
'#source_entity' => $webform_submission
->getSourceEntity(TRUE),
'#webform_submission' => $webform_submission,
];
$form['actions'] = [
'#type' => 'actions',
'#attributes' => [
'style' => 'display:none',
],
'#process' => [],
];
$form['actions']['reset'] = [
'#type' => 'submit',
'#value' => $this
->t('Reset'),
'#validate' => [
'::noValidate',
],
'#submit' => [
'::reset',
],
'#attributes' => [
'style' => 'display:none',
'class' => [
'js-webform-confirmation-back-submit-ajax',
],
],
];
return $form;
}
if (($webform_submission
->isNew() || $webform_submission
->isDraft()) && $webform
->isClosed()) {
if ($webform
->isTemplate() && $webform
->access('duplicate') && !$webform
->isArchived()) {
if (!$this
->isDialog()) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::TEMPLATE_PREVIEW, 'warning');
}
}
elseif ($webform
->access('submission_update_any')) {
$form = $this
->getMessageManager()
->append($form, $webform
->isArchived() ? WebformMessageManagerInterface::ADMIN_ARCHIVED : WebformMessageManagerInterface::ADMIN_CLOSED, 'info');
}
else {
if ($webform
->isOpening()) {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_OPEN_MESSAGE);
}
else {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_CLOSE_MESSAGE);
}
}
}
if ($this
->isConfidential() && $this
->currentUser()
->isAuthenticated() && $this->entity
->isNew() && $this->operation === 'add') {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_CONFIDENTIAL_MESSAGE, 'warning');
}
if ($this
->getWebformSetting('results_disabled') && !$this
->getWebformSetting('results_disabled_ignore') && !$webform
->getHandlers(NULL, TRUE, WebformHandlerInterface::RESULTS_PROCESSED)
->count()) {
$this
->getMessageManager()
->log(WebformMessageManagerInterface::FORM_SAVE_EXCEPTION, 'error');
if ($this
->currentUser()
->hasPermission('administer webform')) {
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_SAVE_EXCEPTION, 'error');
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::ADMIN_CLOSED, 'info');
}
else {
return $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::FORM_EXCEPTION_MESSAGE, 'warning');
}
}
if ($this
->checkTotalLimit() && empty($this
->getWebformSetting('limit_total_unique'))) {
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::LIMIT_TOTAL_MESSAGE, 'warning');
if ($webform
->access('submission_update_any')) {
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::ADMIN_CLOSED, 'info');
return FALSE;
}
else {
return $form;
}
}
if ($this
->checkUserLimit() && empty($this
->getWebformSetting('limit_user_unique'))) {
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::LIMIT_USER_MESSAGE, 'warning');
if ($webform
->access('submission_update_any')) {
$form = $this
->getMessageManager()
->append($form, WebformMessageManagerInterface::ADMIN_CLOSED, 'info');
return FALSE;
}
else {
return $form;
}
}
return FALSE;
}
protected function displayMessages(array $form, FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
$webform = $this
->getWebform();
$source_entity = $this
->getSourceEntity();
$account = $this
->currentUser();
if ($this
->isGet() && $this->operation === 'test' && !$this
->isSharePage()) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_TEST, 'warning');
if ($this->moduleHandler
->moduleExists('devel_generate') && $this
->currentUser()
->hasPermission('administer webform')) {
$query = [
'webform_id' => $webform
->id(),
];
if ($source_entity) {
$query += [
'entity_type' => $source_entity
->getEntityTypeId(),
'entity_id' => $source_entity
->id(),
];
}
$query['destination'] = $this->requestHandler
->getUrl($webform, $source_entity, 'webform.results_submissions')
->toString();
$offcanvas = WebformDialogHelper::useOffCanvas();
$build = [
'#type' => 'link',
'#title' => $this
->t('Generate %title submissions', [
'%title' => $webform
->label(),
]),
'#url' => Url::fromRoute('devel_generate.webform_submission', [], [
'query' => $query,
]),
'#attributes' => $offcanvas ? WebformDialogHelper::getOffCanvasDialogAttributes(400) : [
'class' => [
'button',
],
],
];
if ($offcanvas) {
WebformDialogHelper::attachLibraries($form);
}
$this
->messenger()
->addWarning($this->renderer
->renderPlain($build));
}
}
if ($this
->isGet() && $this
->isRoute('webform.canonical') && $this
->getRouteMatch()
->getRawParameter('webform') === $webform
->id() && !$this
->getWebform()
->getSetting('page')) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::ADMIN_PAGE, 'info');
}
if ($webform_submission
->isDraft()) {
if ($form_state
->get('draft_saved')) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_DRAFT_SAVED_MESSAGE);
$form_state
->set('draft_saved', FALSE);
}
elseif ($this
->isGet() && !$webform
->getSetting('draft_multiple') && !$webform
->isClosed()) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_DRAFT_LOADED_MESSAGE);
}
}
if ($this
->isGet() && $this->operation === 'add' && $this
->getWebformSetting('draft') !== WebformInterface::DRAFT_NONE && $this
->getWebformSetting('draft_multiple', FALSE) && ($previous_draft_total = $this
->getStorage()
->getTotal($webform, $this->sourceEntity, $this
->currentUser(), [
'in_draft' => TRUE,
]))) {
if ($previous_draft_total > 1) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::DRAFT_PENDING_MULTIPLE);
}
else {
$draft_submission = $this
->getStorage()
->loadDraft($webform, $this->sourceEntity, $this
->currentUser());
if (!$draft_submission || $webform_submission
->id() !== $draft_submission
->id()) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::DRAFT_PENDING_SINGLE);
}
}
}
if ($this
->isGet() && $this->operation === 'add' && $this
->getWebformSetting('form_previous_submissions', FALSE) && ($webform
->access('submission_view_own') || $this
->currentUser()
->hasPermission('view own webform submission')) && ($previous_submission_total = $this
->getStorage()
->getTotal($webform, $this->sourceEntity, $this
->currentUser()))) {
if ($previous_submission_total > 1) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::PREVIOUS_SUBMISSIONS);
}
else {
$last_submission = $this
->getStorage()
->getLastSubmission($webform, $source_entity, $account);
if ($last_submission && $webform_submission
->id() !== $last_submission
->id()) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::PREVIOUS_SUBMISSION);
}
}
}
if ($this
->isGet() && $this->operation === 'add' && $webform_submission
->isNew() && $webform
->getSetting('autofill') && $this
->getStorage()
->getLastSubmission($webform, $source_entity, $account, [
'in_draft' => FALSE,
'access_check' => FALSE,
])) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::AUTOFILL_MESSAGE);
}
}
protected function attachLibraries(array &$form, FormStateInterface $form_state) {
$form['#attached']['library'][] = 'webform/webform.form';
$webform = $this
->getWebform();
$assets = $webform
->getAssets();
foreach ($assets as $type => $value) {
if ($value) {
$form['#attached']['library'][] = 'webform/webform.' . $type . '.' . $webform
->id();
}
}
}
protected function attachBehaviors(array &$form, FormStateInterface $form_state) {
if ($this
->getWebformSetting('form_disable_inline_errors')) {
$form['#disable_inline_form_errors'] = TRUE;
}
if ($this
->getWebformSetting('form_novalidate')) {
$form['#attributes']['novalidate'] = 'novalidate';
}
if ($this
->getWebformSetting('form_disable_autocomplete')) {
$form['#attributes']['autocomplete'] = 'off';
}
if ($this
->getWebformSetting('form_disable_back')) {
$form['#attached']['library'][] = 'webform/webform.form.disable_back';
}
if ($this
->getWebformSetting('form_submit_back') && !$this
->isAjax()) {
$form['#attached']['library'][] = 'webform/webform.form.submit_back';
}
if ($this
->getWebformSetting('form_unsaved')) {
$form['#attributes']['class'][] = 'js-webform-unsaved';
$pages = $this
->getPages($form, $form_state);
$current_page = $this
->getCurrentPage($form, $form_state);
if ($current_page && $current_page !== $this
->getFirstPage($pages)) {
$form['#attributes']['data-webform-unsaved'] = TRUE;
}
$form['#attached']['library'][] = 'webform/webform.form.unsaved';
}
if ($this
->getWebformSetting('form_submit_once')) {
$form['#attributes']['class'][] = 'js-webform-submit-once';
$form['#attached']['library'][] = 'webform/webform.form.submit_once';
}
if ($this
->hasPages()) {
$form['#attributes']['class'][] = 'js-webform-disable-autosubmit';
}
if ($this->entity
->isNew() && $this
->getWebformSetting('form_autofocus')) {
$form['#attributes']['class'][] = 'js-webform-autofocus';
$form['#attached']['library'][] = 'webform/webform.form.auto_focus';
}
if ($this
->config('webform.settings')
->get('ui.details_save')) {
$form['#attached']['library'][] = 'webform/webform.element.details.save';
}
if ($this
->getWebformSetting('form_details_toggle')) {
$form['#attributes']['class'][] = 'js-webform-details-toggle';
$form['#attributes']['class'][] = 'webform-details-toggle';
$form['#attached']['library'][] = 'webform/webform.element.details.toggle';
}
}
public function afterBuild(array $form, FormStateInterface $form_state) {
if (strpos($form['#action'], 'form_action_') === FALSE) {
foreach (Element::children($form['actions']) as $child_key) {
unset($form['actions'][$child_key]['#name']);
}
unset($form['form_build_id'], $form['form_token'], $form['form_id']);
}
return $form;
}
protected function pagesElement(array $form, FormStateInterface $form_state) {
$pages = $this
->getPages($form, $form_state);
if (!$pages) {
return NULL;
}
$current_page_name = $this
->getCurrentPage($form, $form_state);
if (!$this
->getWebformSetting('wizard_progress_link') && !($this
->getWebformSetting('wizard_preview_link') && $current_page_name === WebformInterface::PAGE_PREVIEW)) {
return NULL;
}
$page_indexes = array_flip(array_keys($pages));
$current_index = $page_indexes[$current_page_name] - 1;
$element = [
'#type' => 'actions',
'#weight' => -20,
'#attributes' => [
'class' => [
'webform-wizard-pages-links',
'js-webform-wizard-pages-links',
],
],
'#process' => [
[
'\\Drupal\\Core\\Render\\Element\\Actions',
'processContainer',
],
],
];
if ($this
->getWebformSetting('wizard_progress_link')) {
$element['#attributes']['data-wizard-progress-link'] = 'true';
}
if ($this
->getWebformSetting('wizard_preview_link')) {
$element['#attributes']['data-wizard-preview-link'] = 'true';
}
$index = 1;
$total = count($pages);
foreach ($pages as $page_name => $page) {
$access = $page['#access'] && $page_indexes[$page_name] <= $current_index ? TRUE : FALSE;
$t_args = [
'@label' => $page['#title'],
'@start' => $index++,
'@end' => $total,
];
$element[$page_name] = [
'#type' => 'submit',
'#value' => $this
->t('Edit'),
'#page' => $page_name,
'#validate' => [
'::noValidate',
],
'#submit' => [
'::gotoPage',
],
'#name' => 'webform_wizard_page-' . $page_name,
'#attributes' => [
'data-webform-page' => $page_name,
'formnovalidate' => 'formnovalidate',
'class' => [
'webform-wizard-pages-link',
'js-webform-wizard-pages-link',
],
'title' => $this
->t("Edit '@label' (@start of @end)", $t_args),
],
'#access' => $access,
];
}
$element['#attached']['library'][] = 'webform/webform.wizard.pages';
return $element;
}
protected function actionsElement(array $form, FormStateInterface $form_state) {
if (!empty($form['#custom_form'])) {
return NULL;
}
$element = parent::actionsElement($form, $form_state);
if (!empty($element)) {
$element['#theme'] = 'webform_actions';
}
return $element;
}
protected function actions(array $form, FormStateInterface $form_state) {
$webform_submission = $this->entity;
$element = parent::actions($form, $form_state);
$preview_mode = $this
->getWebformSetting('preview');
$element['submit']['#button_type'] = 'primary';
$element['submit']['#attributes']['class'][] = 'webform-button--submit';
$element['submit']['#weight'] = 10;
if ($webform_submission
->isNew() || $webform_submission
->isDraft()) {
$element['submit']['#value'] = $this
->config('webform.settings')
->get('settings.default_submit_button_label');
}
$element['submit']['#validate'][] = '::validateForm';
$element['submit']['#validate'][] = '::autosave';
$element['submit']['#validate'][] = '::complete';
$element['submit']['#submit'][] = '::confirmForm';
if (isset($element['delete'])) {
$element['delete']['#access'] = FALSE;
$element['delete']['#title'] = $this
->config('webform.settings')
->get('settings.default_delete_button_label');
if ($this->operation === 'add') {
$element['delete']['#url']
->mergeOptions([
'query' => $this
->getRedirectDestination()
->getAsArray(),
]);
}
$element['delete']['#weight'] = 20;
}
$pages = $this
->getPages($form, $form_state);
$current_page = $this
->getCurrentPage($form, $form_state);
if ($pages) {
$current_page_element = $this
->getWebform()
->getPage($this->operation, $current_page);
$previous_page = $this
->getPreviousPage($pages, $current_page);
$next_page = $this
->getNextPage($pages, $current_page);
$track = $this
->getWebform()
->getSetting('wizard_track');
switch ($track) {
case 'index':
$track_pages = array_flip(array_keys($pages));
$track_previous_page = $previous_page ? $track_pages[$previous_page] + 1 : NULL;
$track_next_page = $next_page ? $track_pages[$next_page] + 1 : NULL;
$track_last_page = $this
->getWebform()
->getSetting('wizard_confirmation') ? count($track_pages) : count($track_pages) + 1;
break;
default:
case 'name':
$track_previous_page = $previous_page;
$track_next_page = $next_page;
$track_last_page = WebformInterface::PAGE_CONFIRMATION;
break;
}
$is_first_page = $current_page === $this
->getFirstPage($pages) ? TRUE : FALSE;
$is_last_page = in_array($current_page, [
WebformInterface::PAGE_PREVIEW,
WebformInterface::PAGE_CONFIRMATION,
$this
->getLastPage($pages),
]) ? TRUE : FALSE;
$is_preview_page = $current_page === WebformInterface::PAGE_PREVIEW;
$is_next_page_preview = $next_page === WebformInterface::PAGE_PREVIEW ? TRUE : FALSE;
$is_next_page_complete = $next_page === WebformInterface::PAGE_CONFIRMATION ? TRUE : FALSE;
$is_next_page_optional_preview = $is_next_page_preview && $preview_mode !== DRUPAL_REQUIRED;
$element['submit']['#access'] = $is_last_page || $is_preview_page || $is_next_page_optional_preview || $is_next_page_complete;
$element['submit']['#submit'] = [
'::submit',
];
if ($track) {
$element['submit']['#attributes']['data-webform-wizard-page'] = $track_last_page;
}
if (!$is_first_page) {
if ($is_preview_page) {
$element['preview_prev'] = [
'#type' => 'submit',
'#value' => $this
->config('webform.settings')
->get('settings.default_preview_prev_button_label'),
'#validate' => [
'::noValidate',
],
'#submit' => [
'::previous',
],
'#attributes' => [
'formnovalidate' => 'formnovalidate',
'class' => [
'webform-button--previous',
],
],
'#weight' => 0,
];
if ($track) {
$element['preview_prev']['#attributes']['data-webform-wizard-page'] = $track_previous_page;
}
}
else {
if (isset($current_page_element['#prev_button_label'])) {
$previous_button_label = $current_page_element['#prev_button_label'];
$previous_button_custom = TRUE;
}
else {
$previous_button_label = $this
->config('webform.settings')
->get('settings.default_wizard_prev_button_label');
$previous_button_custom = FALSE;
}
$element['wizard_prev'] = [
'#type' => 'submit',
'#value' => $previous_button_label,
'#webform_actions_button_custom' => $previous_button_custom,
'#validate' => [
'::noValidate',
],
'#submit' => [
'::previous',
],
'#attributes' => [
'formnovalidate' => 'formnovalidate',
'class' => [
'webform-button--previous',
],
],
'#weight' => 0,
];
if ($track) {
$element['wizard_prev']['#attributes']['data-webform-wizard-page'] = $track_previous_page;
}
}
}
if (!$is_last_page && !$is_next_page_complete) {
if ($is_next_page_preview) {
$element['preview_next'] = [
'#type' => 'submit',
'#value' => $this
->config('webform.settings')
->get('settings.default_preview_next_button_label'),
'#validate' => [
'::validateForm',
],
'#submit' => [
'::next',
],
'#attributes' => [
'class' => [
'webform-button--preview',
],
],
'#weight' => 1,
];
if ($track) {
$element['preview_next']['#attributes']['data-webform-wizard-page'] = $track_next_page;
}
}
else {
if (isset($current_page_element['#next_button_label'])) {
$next_button_label = $current_page_element['#next_button_label'];
$next_button_custom = TRUE;
}
else {
$next_button_label = $this
->config('webform.settings')
->get('settings.default_wizard_next_button_label');
$next_button_custom = FALSE;
}
$element['wizard_next'] = [
'#type' => 'submit',
'#value' => $next_button_label,
'#webform_actions_button_custom' => $next_button_custom,
'#validate' => [
'::validateForm',
],
'#submit' => [
'::next',
],
'#attributes' => [
'class' => [
'webform-button--next',
],
],
'#weight' => 1,
];
if ($track) {
$element['wizard_next']['#attributes']['data-webform-wizard-page'] = $track_next_page;
}
}
}
if ($track) {
$element['#attached']['library'][] = 'webform/webform.wizard.track';
}
}
if ($this
->draftEnabled()) {
$element['draft'] = [
'#type' => 'submit',
'#value' => $this
->config('webform.settings')
->get('settings.default_draft_button_label'),
'#validate' => [
'::draft',
],
'#submit' => [
'::submitForm',
'::save',
'::rebuild',
],
'#attributes' => [
'formnovalidate' => 'formnovalidate',
'class' => [
'webform-button--draft',
],
],
'#weight' => -10,
];
}
if ($this
->resetEnabled()) {
$element['reset'] = [
'#type' => 'submit',
'#value' => $this
->config('webform.settings')
->get('settings.default_reset_button_label'),
'#validate' => [
'::noValidate',
],
'#submit' => [
'::reset',
],
'#attributes' => [
'formnovalidate' => 'formnovalidate',
'class' => [
'webform-button--reset',
],
],
'#weight' => 10,
];
}
uasort($element, [
'Drupal\\Component\\Utility\\SortArray',
'sortByWeightProperty',
]);
return $element;
}
public function gotoPage(array &$form, FormStateInterface $form_state) {
$element = $form_state
->getTriggeringElement();
$form_state
->set('current_page', $element['#page']);
$this
->wizardSubmit($form, $form_state);
}
public function submit(array &$form, FormStateInterface $form_state) {
$this
->next($form, $form_state, TRUE);
}
public function next(array &$form, FormStateInterface $form_state, $skip_preview = FALSE) {
if ($form_state
->getErrors()) {
return;
}
$pages = $this
->getPages($form, $form_state);
$current_page = $this
->getCurrentPage($form, $form_state);
$next_page = $this
->getNextPage($pages, $current_page);
if (empty($next_page)) {
$next_page = WebformInterface::PAGE_CONFIRMATION;
}
if ($skip_preview && $next_page === WebformInterface::PAGE_PREVIEW) {
$next_page = WebformInterface::PAGE_CONFIRMATION;
}
$form_state
->set('current_page', $next_page);
$this
->wizardSubmit($form, $form_state);
}
public function previous(array &$form, FormStateInterface $form_state) {
$pages = $this
->getPages($form, $form_state);
$current_page = $this
->getCurrentPage($form, $form_state);
$previous_page = $this
->getPreviousPage($pages, $current_page);
$form_state
->set('current_page', $previous_page);
$this
->wizardSubmit($form, $form_state);
}
protected function wizardSubmit(array &$form, FormStateInterface $form_state) {
$current_page = $form_state
->get('current_page');
if ($current_page === WebformInterface::PAGE_CONFIRMATION) {
$this
->complete($form, $form_state);
$this
->submitForm($form, $form_state);
$this
->save($form, $form_state);
$this
->confirmForm($form, $form_state);
}
elseif ($this
->draftEnabled() && $this
->getWebformSetting('draft_auto_save') && !$this->entity
->isCompleted()) {
$form_state
->set('in_draft', TRUE);
$this
->submitForm($form, $form_state);
$this
->save($form, $form_state);
$this
->rebuild($form, $form_state);
}
else {
$this
->submitForm($form, $form_state);
$this
->rebuild($form, $form_state);
}
if ($this
->isAjax()) {
$pages = $this
->getPages($form, $form_state);
if (isset($pages[$current_page])) {
$page_keys = array_keys($pages);
$page_indexes = array_flip($page_keys);
$total_pages = count($page_keys);
$current_index = $page_indexes[$current_page];
$t_args = [
'@title' => $this
->getWebform()
->label(),
'@page' => $pages[$current_page]['#title'],
'@start' => $current_index + 1,
'@end' => $total_pages,
];
$this
->announce($this
->t('"@title: @page" loaded. (@start of @end)', $t_args));
}
}
}
public function autosave(array &$form, FormStateInterface $form_state) {
if ($form_state
->hasAnyErrors()) {
if ($this
->draftEnabled() && $this
->getWebformSetting('draft_auto_save') && !$this->entity
->isCompleted()) {
$form_state
->set('in_draft', TRUE);
$was_new = $this->entity
->isNew();
$this
->submitForm($form, $form_state);
$this
->save($form, $form_state);
$this
->rebuild($form, $form_state);
if ($was_new && $form_state
->hasAnyErrors()) {
$this->formBuilder
->deleteCache($form['#build_id']);
}
}
}
}
public function draft(array &$form, FormStateInterface $form_state) {
$form_state
->clearErrors();
$form_state
->set('in_draft', TRUE);
$form_state
->set('draft_saved', TRUE);
$this->entity
->validate();
}
public function complete(array &$form, FormStateInterface $form_state) {
$form_state
->set('in_draft', FALSE);
}
public function noValidate(array &$form, FormStateInterface $form_state) {
$form_state
->clearErrors();
$this->entity
->validate();
}
public function rebuild(array &$form, FormStateInterface $form_state) {
$form_state
->setRebuild();
}
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
if ($this->operation === 'api') {
$form['#disable_inline_form_errors'] = TRUE;
}
$this->entity = $this
->buildEntity($form, $form_state);
$this->conditionsValidator
->validateForm($form, $form_state);
$this
->getWebform()
->invokeHandlers('validateForm', $form, $form_state, $this->entity);
$trigger_element = $form_state
->getTriggeringElement();
if (isset($trigger_element['#validate'])) {
$handlers = array_filter($form['#validate'], function ($callback) {
return is_array($callback) || $callback !== '::validateForm';
});
foreach ($handlers as $callback) {
$arguments = [
&$form,
&$form_state,
];
call_user_func_array($form_state
->prepareCallback($callback), $arguments);
}
}
$this
->validateUploadedManagedFiles($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$this->conditionsValidator
->submitForm($form, $form_state);
$this
->getWebform()
->invokeHandlers('submitForm', $form, $form_state, $this->entity);
}
public function confirmForm(array &$form, FormStateInterface $form_state) {
$this
->setConfirmation($form_state);
$webform_submission = $this
->getEntity();
$this
->getWebform()
->invokeHandlers('confirmForm', $form, $form_state, $webform_submission);
$confirmation_type = $this
->getWebformSetting('confirmation_type');
$state = $webform_submission
->getState();
if ($this
->isAjax()) {
if ($state === WebformSubmissionInterface::STATE_UPDATED) {
if (!$this
->getRequest()
->get('destination')) {
$this
->rebuild($form, $form_state);
}
}
elseif ($confirmation_type === WebformInterface::CONFIRMATION_MESSAGE || $confirmation_type === WebformInterface::CONFIRMATION_NONE) {
$this
->reset($form, $form_state);
}
}
if ($confirmation_type === WebformInterface::CONFIRMATION_MODAL) {
if ($state === WebformSubmissionInterface::STATE_UPDATED) {
$this
->rebuild($form, $form_state);
}
else {
$this
->reset($form, $form_state);
}
}
}
public function save(array $form, FormStateInterface $form_state) {
$webform = $this
->getWebform();
$webform_submission = $this
->getEntity();
$webform
->applyVariants($webform_submission);
if ($webform_submission
->isNew()) {
if (preg_match('/\\.webform\\.test_form$/', $this
->getRouteMatch()
->getRouteName())) {
$source_url = $webform_submission
->set('uri', NULL)
->getSourceUrl()
->setAbsolute(FALSE);
$uri = preg_replace('#^' . base_path() . '#', '/', $source_url
->toString());
}
else {
$uri = preg_replace('#^' . base_path() . '#', '/', $this
->getRequest()
->getRequestUri());
$uri = preg_replace('/(ajax_form=1|_wrapper_format=(drupal_ajax|drupal_modal|drupal_dialog|html|ajax))(&|$)/', '', $uri);
$uri = preg_replace('/\\?$/', '', $uri);
}
$webform_submission
->set('uri', $uri);
$webform_submission
->set('remote_addr', $this
->getWebform()
->hasRemoteAddr() ? $this
->getRequest()
->getClientIp() : '');
if ($this
->isConfidential()) {
$webform_submission
->setOwnerId(0);
}
}
if ($webform
->isTemplate() && !$webform
->access('update')) {
return;
}
$webform_submission
->save();
if ($this
->getWebformSetting('limit_total') || $this
->getWebformSetting('user_limit_total') || $this
->getWebformSetting('entity_limit_total') || $this
->getWebformSetting('entity_limit_user') || $this
->getWebformSetting('limit_total_unique') || $this
->getWebformSetting('limit_user_unique')) {
Cache::invalidateTags([
'webform:' . $this
->getWebform()
->id(),
]);
}
if ($this
->checkTotalLimit() || $this
->checkUserLimit()) {
$form_state
->setRebuild();
}
}
public function reset(array &$form, FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
if ($webform_submission
->isDraft()) {
$webform_submission
->delete();
}
$webform_submission = $this
->getEntity()
->createDuplicate();
$webform_submission
->setData($this->originalData);
$this
->setEntity($webform_submission);
$form_state
->setUserInput(array_intersect_key($form_state
->getUserInput(), [
'form_build_id' => 'form_build_id',
'form_token' => 'form_token',
'form_id' => 'form_id',
]));
$form_state
->setValues([]);
$storage = $form_state
->getStorage();
unset($storage['current_page']);
$form_state
->setStorage($storage);
$this
->rebuild($form, $form_state);
}
protected function validateUploadedManagedFiles(array $form, FormStateInterface $form_state) {
$file_limit = $this
->getWebform()
->getSetting('form_file_limit') ?: $this->configFactory
->get('webform.settings')
->get('settings.default_form_file_limit') ?: '';
$file_limit = Bytes::toInt($file_limit);
if (!$file_limit) {
return;
}
$fids = $this
->getUploadedManagedFileIds();
if (!$fids) {
return;
}
$file_names = [];
$total_file_size = 0;
$files = $this->entityTypeManager
->getStorage('file')
->loadMultiple($fids);
foreach ($files as $file) {
$total_file_size += (int) $file
->getSize();
$file_names[] = $file
->getFilename() . ' - ' . format_size($file
->getSize(), $this->entity
->language()
->getId());
}
if ($total_file_size > $file_limit) {
$t_args = [
'%quota' => format_size($file_limit),
];
$message = [];
$message['content'] = [
'#markup' => $this
->t("This form's file upload quota of %quota has been exceeded. Please remove some files.", $t_args),
];
$message['files'] = [
'#theme' => 'item_list',
'#items' => $file_names,
];
$form_state
->setErrorByName(NULL, $this->renderer
->renderPlain($message));
}
}
protected function getUploadedManagedFileIds() {
$fids = [];
$element_keys = $this
->getWebform()
->getElementsManagedFiles();
foreach ($element_keys as $element_key) {
$data = $this->entity
->getElementData($element_key);
if (!$data) {
continue;
}
$element = $this
->getWebform()
->getElement($element_key);
$element_plugin = $this->elementManager
->getElementInstance($element);
$multiple = $element_plugin
->hasMultipleValues($element);
if ($element_plugin instanceof WebformCompositeBase) {
$managed_file_keys = $element_plugin
->getManagedFiles($element);
$data = !$multiple ? [
$data,
] : $data;
foreach ($data as $item) {
foreach ($managed_file_keys as $manage_file_key) {
if ($item[$manage_file_key]) {
$fids[] = $item[$manage_file_key];
}
}
}
}
else {
$fids = array_merge($fids, (array) $data);
}
}
return $fids;
}
protected function setFormPropertiesFromElements(array &$form, array &$elements) {
foreach ($elements as $key => $value) {
if (is_string($key) && $key[0] === '#') {
$value = $this->tokenManager
->replace($value, $this
->getEntity(), [], [], $this->bubbleableMetadata);
if (isset($form[$key]) && is_array($form[$key]) && is_array($value)) {
$form[$key] = NestedArray::mergeDeep($form[$key], $value);
}
else {
$form[$key] = $value;
}
unset($elements[$key], $form['elements'][$key]);
}
}
if (isset($form['#attributes'])) {
$form['#attributes'] = $this->tokenManager
->replace($form['#attributes'], $this
->getEntity(), [], [], $this->bubbleableMetadata);
}
}
protected function hasPages() {
return $this
->getWebform()
->getPages($this->operation);
}
protected function getPages(array &$form, FormStateInterface $form_state) {
if ($form_state
->get('pages') === NULL) {
$pages = $this
->getWebform()
->getPages($this->operation);
$form_state
->set('pages', $pages);
}
$pages = $form_state
->get('pages');
$webform_submission = $this
->getEntity();
return $this->conditionsValidator
->buildPages($pages, $webform_submission);
}
protected function getCurrentPage(array &$form, FormStateInterface $form_state) {
if ($form_state
->get('current_page') === NULL) {
$pages = $this
->getWebform()
->getPages($this->operation);
if (empty($pages)) {
$form_state
->set('current_page', '');
}
else {
$current_page = $this->entity
->getCurrentPage();
if ($current_page && isset($pages[$current_page]) && !$this->entity
->isCompleted()) {
$form_state
->set('current_page', $current_page);
}
else {
$form_state
->set('current_page', WebformArrayHelper::getFirstKey($pages));
}
}
}
return $form_state
->get('current_page');
}
protected function getFirstPage(array $pages) {
return WebformArrayHelper::getFirstKey($pages);
}
protected function getLastPage(array $pages) {
return WebformArrayHelper::getLastKey($pages);
}
protected function getNextPage(array $pages, $current_page) {
return WebformArrayHelper::getNextKey($pages, $current_page);
}
protected function getPreviousPage(array $pages, $current_page) {
return WebformArrayHelper::getPreviousKey($pages, $current_page);
}
protected function displayCurrentPage(array &$form, FormStateInterface $form_state) {
$current_page = $this
->getCurrentPage($form, $form_state);
if ($current_page === WebformInterface::PAGE_PREVIEW) {
foreach ($form['elements'] as $element_key => $element) {
if (isset($element['#type']) && $element['#type'] === 'webform_actions') {
continue;
}
if (Element::child($element_key) && is_array($form['elements'])) {
WebformElementHelper::setPropertyRecursive($form['elements'][$element_key], '#access', FALSE);
}
}
$this
->getMessageManager()
->display(WebformMessageManagerInterface::FORM_PREVIEW_MESSAGE, 'warning');
$preview_attributes = new Attribute($this
->getWebform()
->getSetting('preview_attributes'));
$preview_attributes
->addClass('webform-preview');
$form['#title'] = PlainTextOutput::renderFromHtml($this
->getWebformSetting('preview_title'));
$form['preview'] = [
'#type' => 'container',
'#attributes' => $preview_attributes,
'#weight' => -10,
'submission' => $this->entityTypeManager
->getViewBuilder('webform_submission')
->view($this->entity, 'preview'),
];
}
else {
$pages = $this
->getWebform()
->getPages($this->operation);
foreach ($pages as $page_key => $page) {
if (isset($form['elements'][$page_key])) {
$page_element =& $form['elements'][$page_key];
$page_element_plugin = $this->elementManager
->getElementInstance($page_element);
if ($page_element_plugin instanceof WebformElementWizardPageInterface) {
if ($page_key != $current_page) {
$page_element_plugin
->hidePage($page_element);
}
else {
$page_element_plugin
->showPage($page_element);
}
}
}
}
}
}
protected function setTrustedRedirectUrl(FormStateInterface $form_state, Url $url) {
$form_state
->setResponse(new TrustedRedirectResponse($url
->setAbsolute()
->toString()));
}
protected function setConfirmation(FormStateInterface $form_state) {
$webform_submission = $this
->getEntity();
$webform = $webform_submission
->getWebform();
$route_name = $this
->getRouteMatch()
->getRouteName();
$route_parameters = $this
->getRouteMatch()
->getRawParameters()
->all();
$route_options = [];
if (!$webform
->getSetting('confirmation_exclude_query')) {
$query = $this
->getRequest()->query
->all();
unset($query['ajax_form'], $query['_wrapper_format']);
if ($query) {
$route_options['query'] = $query;
}
}
$state = $webform_submission
->getState();
$is_updated = $state === WebformSubmissionInterface::STATE_UPDATED;
$is_locked = $state === WebformSubmissionInterface::STATE_LOCKED && $webform_submission
->getChangedTime() > $webform_submission
->getCompletedTime();
$confirmation_update = $this
->getWebformSetting('confirmation_update');
if ($is_updated && !$confirmation_update || $is_locked) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_UPDATED);
$form_state
->set('current_page', NULL);
$form_state
->setRedirect($route_name, $route_parameters, $route_options);
return;
}
if ($state === WebformSubmissionInterface::STATE_COMPLETED && !$webform
->getSetting('confirmation_exclude_token')) {
$route_options['query']['token'] = $webform_submission
->getToken();
}
$confirmation_type = $this
->getWebformSetting('confirmation_type');
switch ($confirmation_type) {
case WebformInterface::CONFIRMATION_PAGE:
$redirect_url = $this->requestHandler
->getUrl($webform, $this->sourceEntity, 'webform.confirmation', $route_options);
$form_state
->setRedirectUrl($redirect_url);
return;
case WebformInterface::CONFIRMATION_URL:
case WebformInterface::CONFIRMATION_URL_MESSAGE:
$redirect_url = $this
->getConfirmationUrl();
if ($redirect_url) {
if ($confirmation_type === WebformInterface::CONFIRMATION_URL_MESSAGE) {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_CONFIRMATION_MESSAGE);
}
$this
->setTrustedRedirectUrl($form_state, $redirect_url);
}
else {
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_CONFIRMATION_MESSAGE);
$route_options['query']['webform_id'] = $webform
->id();
$form_state
->setRedirect($route_name, $route_parameters, $route_options);
}
return;
case WebformInterface::CONFIRMATION_INLINE:
$form_state
->set('current_page', WebformInterface::PAGE_CONFIRMATION);
$form_state
->setRebuild();
return;
case WebformInterface::CONFIRMATION_MESSAGE:
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_CONFIRMATION_MESSAGE);
return;
case WebformInterface::CONFIRMATION_MODAL:
$message = $this
->getMessageManager()
->build(WebformMessageManagerInterface::SUBMISSION_CONFIRMATION_MESSAGE);
if ($message) {
$form_state
->set('webform_confirmation_modal', [
'title' => $this
->getWebformSetting('confirmation_title', ''),
'content' => $message,
]);
}
return;
case WebformInterface::CONFIRMATION_NONE:
return;
case WebformInterface::CONFIRMATION_DEFAULT:
default:
$this
->getMessageManager()
->display(WebformMessageManagerInterface::SUBMISSION_DEFAULT_CONFIRMATION);
return;
}
}
protected function getConfirmationUrl() {
$confirmation_url = trim($this
->getWebformSetting('confirmation_url', ''));
if (strpos($confirmation_url, '/') === 0) {
$redirect_url = Url::fromUri($this
->getRequest()
->getSchemeAndHttpHost() . $confirmation_url);
}
elseif (preg_match('#^[a-z]+(?:://|:)#', $confirmation_url)) {
$redirect_url = Url::fromUri($confirmation_url);
}
elseif (strpos($confirmation_url, '<') === 0) {
$redirect_url = $this->pathValidator
->getUrlIfValid($confirmation_url);
}
else {
$confirmation_url = $this->aliasManager
->getPathByAlias('/' . $confirmation_url);
$redirect_url = $this->pathValidator
->getUrlIfValid($confirmation_url);
}
if (!$redirect_url) {
$webform = $this
->getWebform();
$t_args = [
'@webform' => $webform
->label(),
'%url' => $this
->getWebformSetting('confirmation_url'),
];
if ($webform
->access('update')) {
$this
->messenger()
->addWarning($this
->t('Confirmation URL %url is not valid.', $t_args));
}
$this
->getLogger('webform')
->warning('@webform: Confirmation URL %url is not valid.', $t_args);
}
return $redirect_url;
}
public static function removeConfirmationModal(&$element, FormStateInterface $form_state, &$complete_form) {
$storage = $form_state
->getStorage();
unset($storage['webform_confirmation_modal']);
$form_state
->setStorage($storage);
unset($complete_form['webform_confirmation_modal']);
}
protected function prepareElements(array &$elements, array &$form, FormStateInterface $form_state) {
foreach ($elements as $key => &$element) {
if (!WebformElementHelper::isElement($element, $key)) {
continue;
}
$this->elementManager
->buildElement($element, $form, $form_state);
if (isset($element['#states'])) {
$element['#states'] = $this
->addStatesPrefix($element['#states']);
}
$this
->prepareElements($element, $form, $form_state);
}
}
protected function alterElementsForm(array &$elements, array &$form, FormStateInterface $form_state) {
foreach ($elements as $key => &$element) {
if (!WebformElementHelper::isElement($element, $key)) {
continue;
}
$element_plugin = $this->elementManager
->getElementInstance($element);
if ($element_plugin) {
$element_plugin
->alterForm($element, $form, $form_state);
}
$this
->alterElementsForm($element, $form, $form_state);
}
}
protected function addStatesPrefix(array $array) {
$prefixed_array = [];
foreach ($array as $key => $value) {
if (strpos($key, ':input') === 0) {
$key = $this->statesPrefix . ' ' . $key;
$prefixed_array[$key] = $value;
}
elseif (is_array($value)) {
$prefixed_array[$key] = $this
->addStatesPrefix($value);
}
else {
$prefixed_array[$key] = $value;
}
}
return $prefixed_array;
}
protected function prepopulateData(array &$data) {
if ($this
->getWebformSetting('form_prepopulate')) {
$prepopulate_data = $this
->getRequest()->query
->all();
}
else {
$prepopulate_data = [];
$elements = $this
->getWebform()
->getElementsPrepopulate();
foreach ($elements as $element_key) {
if ($this
->getRequest()->query
->has($element_key)) {
$prepopulate_data[$element_key] = $this
->getRequest()->query
->get($element_key);
}
}
}
foreach ($prepopulate_data as $element_key => &$value) {
if ($this
->checkPrepopulateDataValid($element_key, $value) === FALSE) {
unset($prepopulate_data[$element_key]);
}
}
$data = $prepopulate_data + $data;
}
protected function checkPrepopulateDataValid($element_key, &$value) {
$element = $this
->getWebform()
->getElement($element_key);
if (!$element) {
return FALSE;
}
$element_plugin = $this->elementManager
->getElementInstance($element);
if (!$element_plugin
->isInput($element)) {
return FALSE;
}
if ($element_plugin instanceof WebformElementEntityReferenceInterface) {
if (isset($element['#vocabulary'])) {
$vocabulary_id = $element['#vocabulary'];
$options = [
'target_type' => 'taxonomy_term',
'handler' => 'default:taxonomy_term',
'target_bundles' => [
$vocabulary_id => $vocabulary_id,
],
];
}
elseif (isset($element['#selection_settings'])) {
$options = $element['#selection_settings'] + [
'target_type' => $element['#target_type'],
'handler' => $element['#selection_handler'],
];
}
else {
return TRUE;
}
$handler = $this->selectionManager
->getInstance($options);
$valid_ids = $handler
->validateReferenceableEntities((array) $value);
if (empty($valid_ids)) {
return FALSE;
}
else {
$value = $element_plugin
->hasMultipleValues($element) ? $valid_ids : reset($valid_ids);
return TRUE;
}
}
$is_options_element = isset($element['#options']) && $element_plugin instanceof OptionsBase && !$element_plugin instanceof WebformElementOtherInterface;
if ($is_options_element) {
$option_values = WebformOptionsHelper::validateOptionValues($element['#options'], (array) $value);
if (empty($option_values)) {
return FALSE;
}
else {
$value = $element_plugin
->hasMultipleValues($element) ? $option_values : reset($option_values);
return TRUE;
}
}
return TRUE;
}
protected function populateElements(array &$elements, array $values) {
foreach ($elements as $key => &$element) {
if (!WebformElementHelper::isElement($element, $key)) {
continue;
}
if (!isset($values[$key])) {
$this
->populateElements($element, $values);
continue;
}
$element_plugin = $this->elementManager
->getElementInstance($element);
if (!$element_plugin || !$element_plugin
->isInput($element)) {
$this
->populateElements($element, $values);
continue;
}
if ($this
->getRequest()->query
->has($key) && !$element_plugin
->hasProperty('prepopulate')) {
$this
->populateElements($element, $values);
continue;
}
$is_hidden = $element_plugin instanceof Hidden;
if ($element_plugin
->hasProperty('default_value') || $is_hidden) {
$element['#default_value'] = $values[$key];
}
elseif ($element_plugin
->hasProperty('value')) {
$element['#value'] = $values[$key];
}
if ($this->operation === 'api') {
$element['#needs_validation'] = TRUE;
}
$this
->populateElements($element, $values);
}
}
protected function addCacheableDependency(array &$form) {
$webform_submission = $this
->getEntity();
$submission_storage = $this->entityTypeManager
->getStorage('webform_submission');
if ($this
->currentUser()
->isAnonymous() && $submission_storage
->hasAnonymousSubmissionTracking($webform_submission)) {
$form['#cache']['contexts'][] = 'session';
}
if ($this
->getWebformSetting('form_prepopulate')) {
$form['#cache']['contexts'][] = 'url.query_args';
}
else {
$elements_prepopulate = $this
->getWebform()
->getElementsPrepopulate();
if ($elements_prepopulate) {
foreach ($elements_prepopulate as $element_key) {
$form['#cache']['contexts'][] = 'url.query_args:' . $element_key;
}
}
if ($this
->getWebformSetting('form_prepopulate_source_entity')) {
$form['#cache']['contexts'][] = 'url.query_args:source_entity_type';
$form['#cache']['contexts'][] = 'url.query_args:source_entity_id';
}
if ($this
->getWebform()
->hasVariants()) {
$form['#cache']['contexts'][] = 'url.query_args:_webform_variant';
}
}
}
protected function checkTotalLimit() {
$webform = $this
->getWebform();
$limit_total_unique = $this
->getWebformSetting('limit_total_unique');
$entity_limit_total = $this
->getWebformSetting('entity_limit_total');
$entity_limit_total_interval = $this
->getWebformSetting('entity_limit_total_interval');
if ($limit_total_unique) {
$entity_limit_total = 1;
$entity_limit_total_interval = NULL;
}
if ($entity_limit_total && ($source_entity = $this
->getLimitSourceEntity())) {
if ($this
->getStorage()
->getTotal($webform, $source_entity, NULL, [
'interval' => $entity_limit_total_interval,
]) >= $entity_limit_total) {
return TRUE;
}
}
$limit_total = $this
->getWebformSetting('limit_total');
$limit_total_interval = $this
->getWebformSetting('limit_total_interval');
if ($limit_total_unique) {
$limit_total = 1;
$limit_total_interval = NULL;
}
if ($limit_total && $this
->getStorage()
->getTotal($webform, NULL, NULL, [
'interval' => $limit_total_interval,
]) >= $limit_total) {
return TRUE;
}
return FALSE;
}
protected function checkUserLimit() {
$webform_submission = $this
->getEntity();
if ($webform_submission
->id() && $webform_submission
->isOwner($this
->currentUser())) {
return FALSE;
}
$account = $this->entity
->getOwner();
$webform = $this
->getWebform();
$entity_limit_user = $this
->getWebformSetting('entity_limit_user');
$entity_limit_user_interval = $this
->getWebformSetting('entity_limit_user_interval');
if ($entity_limit_user && ($source_entity = $this
->getLimitSourceEntity())) {
if ($this
->getStorage()
->getTotal($webform, $source_entity, $account, [
'interval' => $entity_limit_user_interval,
]) >= $entity_limit_user) {
return TRUE;
}
}
$limit_user = $this
->getWebformSetting('limit_user');
$limit_user_interval = $this
->getWebformSetting('limit_user_interval');
if ($limit_user && $this
->getStorage()
->getTotal($webform, NULL, $account, [
'interval' => $limit_user_interval,
]) >= $limit_user) {
return TRUE;
}
return FALSE;
}
protected function draftEnabled() {
if ($this
->getWebformSetting('results_disabled')) {
return FALSE;
}
$webform_submission = $this
->getEntity();
if ($webform_submission
->isCompleted()) {
return FALSE;
}
switch ($this
->getWebformSetting('draft')) {
case WebformInterface::DRAFT_ALL:
return TRUE;
case WebformInterface::DRAFT_AUTHENTICATED:
return $webform_submission
->getOwner()
->isAuthenticated();
case WebformInterface::DRAFT_NONE:
default:
return FALSE;
}
}
protected function resetEnabled() {
return $this
->getWebformSetting('form_reset', FALSE);
}
protected function isConfidential() {
return $this
->getWebformSetting('form_confidential', FALSE);
}
protected function isFormNoValidate() {
return $this
->getWebformSetting('form_novalidate', FALSE);
}
protected function isGet() {
return $this
->getRequest()
->getMethod() === 'GET' ? TRUE : FALSE;
}
protected function isRoute($route_name) {
return $this->requestHandler
->getRouteName($this
->getEntity(), $this
->getSourceEntity(), $route_name) === $this
->getRouteMatch()
->getRouteName() ? TRUE : FALSE;
}
protected function isWebformEntityReferenceFromSourceEntity() {
if (!$this->sourceEntity) {
return FALSE;
}
$webform = $this->webformEntityReferenceManager
->getWebform($this->sourceEntity);
if (!$webform) {
return FALSE;
}
return $webform
->id() === $this
->getWebform()
->id() ? TRUE : FALSE;
}
public function getWebform() {
$webform_submission = $this
->getEntity();
return $webform_submission
->getWebform();
}
protected function getSourceEntity() {
return $this->sourceEntity;
}
protected function getStorage() {
return $this->entityTypeManager
->getStorage('webform_submission');
}
protected function getMessageManager() {
$this->messageManager
->setWebformSubmission($this
->getEntity());
return $this->messageManager;
}
protected function getLimitSourceEntity() {
$webform_submission = $this
->getEntity();
$source_entity = $webform_submission
->getSourceEntity();
if ($source_entity && $source_entity
->getEntityTypeId() !== 'webform') {
return $source_entity;
}
return NULL;
}
protected function getWebformSetting($name, $default_value = NULL) {
$value = $this
->getWebform()
->getSetting($name) ?: $this
->config('webform.settings')
->get('settings.default_' . $name) ?: NULL;
if ($value !== NULL) {
return $this->tokenManager
->replace($value, $this
->getEntity(), [], [], $this->bubbleableMetadata);
}
else {
return $default_value;
}
}
protected function isSharePage() {
return strpos($this
->getRouteMatch()
->getRouteName(), 'entity.webform.share_page') === 0;
}
protected function isAjax() {
if ($this->operation === 'api') {
return FALSE;
}
$elements = $this
->getWebform()
->getElementsInitialized();
if (isset($elements['#method']) && $elements['#method'] === 'get') {
return FALSE;
}
return $this
->getWebformSetting('ajax', FALSE);
}
public function cancelAjaxForm(array &$form, FormStateInterface $form_state) {
throw new \Exception('Webform submission Ajax form should never be cancelled. Only ::reset should be called.');
}
public function validateAjaxForm(array &$form, FormStateInterface $form_state) {
if (!$this
->isCallableAjaxCallback($form, $form_state)) {
Cache::invalidateTags([
'webform:' . $this
->getWebform()
->id(),
]);
$this
->missingAjaxCallback($form, $form_state);
}
}
public static function isOpen(WebformInterface $webform) {
$webform_submission = WebformSubmission::create([
'webform_id' => $webform
->id(),
]);
$form_object = \Drupal::entityTypeManager()
->getFormObject('webform_submission', 'add');
$form_object
->setEntity($webform_submission);
$message_manager = \Drupal::service('webform.message_manager');
$message_manager
->setWebformSubmission($webform_submission);
if ($webform
->isClosed()) {
if ($webform
->isOpening()) {
return $message_manager
->get(WebformMessageManagerInterface::FORM_OPEN_MESSAGE);
}
else {
return $message_manager
->get(WebformMessageManagerInterface::FORM_CLOSE_MESSAGE);
}
}
if ($form_object
->checkTotalLimit()) {
return $message_manager
->get(WebformMessageManagerInterface::LIMIT_TOTAL_MESSAGE);
}
if ($form_object
->checkUserLimit()) {
return $message_manager
->get(WebformMessageManagerInterface::LIMIT_USER_MESSAGE);
}
return TRUE;
}
public static function validateFormValues(array $values) {
return static::submitFormValues($values, TRUE);
}
public static function submitFormValues(array $values, $validate_only = FALSE) {
$webform_submission = WebformSubmission::create($values);
return static::submitWebformSubmission($webform_submission, $validate_only);
}
public static function validateWebformSubmission(WebformSubmissionInterface $webform_submission) {
return static::submitWebformSubmission($webform_submission, TRUE);
}
public static function submitWebformSubmission(WebformSubmissionInterface $webform_submission, $validate_only = FALSE) {
$form_object = \Drupal::entityTypeManager()
->getFormObject('webform_submission', 'api');
$form_object
->setEntity($webform_submission);
$form_state = new FormState();
$form_state
->setTriggeringElement([
'#parents' => [],
]);
$error_messages = \Drupal::messenger()
->messagesByType(MessengerInterface::TYPE_ERROR);
\Drupal::formBuilder()
->submitForm($form_object, $form_state);
$errors = $webform_submission
->isDraft() && !$validate_only ? [] : $form_state
->getErrors();
\Drupal::messenger()
->deleteByType(MessengerInterface::TYPE_ERROR);
foreach ($error_messages as $error_message) {
\Drupal::messenger()
->addError($error_message);
}
if ($errors) {
return $errors;
}
elseif ($validate_only) {
return NULL;
}
else {
$webform_submission
->save();
return $webform_submission;
}
}
}