You are here

WebformSubmissionViewBuilder.php in Webform 6.x

Same filename and directory in other branches
  1. 8.5 src/WebformSubmissionViewBuilder.php

Namespace

Drupal\webform

File

src/WebformSubmissionViewBuilder.php
View source
<?php

namespace Drupal\webform;

use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityViewBuilder;
use Drupal\webform\Plugin\WebformElementAttachmentInterface;
use Drupal\webform\Plugin\WebformElementCompositeInterface;
use Drupal\webform\Twig\WebformTwigExtension;
use Drupal\webform\Utility\WebformElementHelper;
use Drupal\webform\Utility\WebformYaml;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Render controller for webform submissions.
 */
class WebformSubmissionViewBuilder extends EntityViewBuilder implements WebformSubmissionViewBuilderInterface {

  /**
   * The route match object.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The webform request handler.
   *
   * @var \Drupal\webform\WebformRequestInterface
   */
  protected $requestHandler;

  /**
   * The webform element manager service.
   *
   * @var \Drupal\webform\Plugin\WebformElementManagerInterface
   */
  protected $elementManager;

  /**
   * The webform submission (server-side) conditions (#states) validator.
   *
   * @var \Drupal\webform\WebformSubmissionConditionsValidator
   */
  protected $conditionsValidator;

  /**
   * {@inheritdoc}
   */
  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    $instance = parent::createInstance($container, $entity_type);
    $instance->requestHandler = $container
      ->get('webform.request');
    $instance->elementManager = $container
      ->get('plugin.manager.webform.element');
    $instance->conditionsValidator = $container
      ->get('webform_submission.conditions_validator');
    $instance->routeMatch = $container
      ->get('current_route_match');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {

    // Allow modules to set custom webform submission view mode.
    // @see \Drupal\webform_entity_print\Plugin\WebformExporter\WebformEntityPrintWebformExporter::writeSubmission
    if ($webform_submissions_view_mode = \Drupal::request()->request
      ->get('_webform_submissions_view_mode')) {
      $view_mode = $webform_submissions_view_mode;
    }

    // Apply variants.

    /** @var \Drupal\webform\WebformSubmissionInterface $entity */

    /** @var \Drupal\webform\WebformInterface $webform */
    $webform = $entity
      ->getWebform();
    $webform
      ->applyVariants($entity);
    return parent::view($entity, $view_mode, $langcode);
  }

  /**
   * {@inheritdoc}
   */
  protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
    $build = parent::getBuildDefaults($entity, $view_mode);

    // The webform submission will be rendered in the wrapped webform submission
    // template already. Instead we are going to wrap the rendered submission
    // in a webform submission data template.
    // @see \Drupal\contact_storage\ContactMessageViewBuilder
    // @see \Drupal\comment\CommentViewBuilder::getBuildDefaults
    // @see \Drupal\block_content\BlockContentViewBuilder::getBuildDefaults
    // @see webform-submission-data.html.twig
    $build['#theme'] = 'webform_submission_data';
    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function buildComponents(array &$build, array $entities, array $displays, $view_mode) {
    if (empty($entities)) {
      return;
    }

    /** @var \Drupal\webform\WebformSubmissionInterface[] $entities */
    foreach ($entities as $id => $webform_submission) {
      $webform = $webform_submission
        ->getWebform();
      if ($view_mode === 'preview') {
        $options = [
          'view_mode' => $view_mode,
          'excluded_elements' => $webform
            ->getSetting('preview_excluded_elements'),
          'exclude_empty' => $webform
            ->getSetting('preview_exclude_empty'),
          'exclude_empty_checkbox' => $webform
            ->getSetting('preview_exclude_empty_checkbox'),
        ];
      }
      else {

        // Track PDF.
        // @see webform_entity_print.module
        $route_name = $this->routeMatch
          ->getRouteName();
        $pdf = in_array($route_name, [
          'entity_print.view.debug',
          'entity_print.view',
        ]) || \Drupal::request()->request
          ->get('_webform_entity_print');
        $options = [
          'view_mode' => $view_mode,
          'excluded_elements' => $webform
            ->getSetting('submission_excluded_elements'),
          'exclude_empty' => $webform
            ->getSetting('submission_exclude_empty'),
          'exclude_empty_checkbox' => $webform
            ->getSetting('submission_exclude_empty_checkbox'),
          'pdf' => $pdf,
        ];
      }
      switch ($view_mode) {
        case 'twig':

          // @see \Drupal\webform_entity_print_attachment\Element\WebformEntityPrintAttachment::getFileContent
          $build[$id]['data'] = WebformTwigExtension::buildTwigTemplate($webform_submission, $webform_submission->_webform_view_mode_twig);
          break;
        case 'yaml':

          // Note that the YAML view ignores all access controls and excluded
          // settings.
          $data = $webform_submission
            ->toArray(TRUE, TRUE);

          // Covert computed element value markup to strings to
          // 'Object support when dumping a YAML file has been disabled' errors.
          WebformElementHelper::convertRenderMarkupToStrings($data);
          $build[$id]['data'] = [
            '#theme' => 'webform_codemirror',
            '#code' => WebformYaml::encode($data),
            '#type' => 'yaml',
          ];
          break;
        case 'text':
          $elements = $webform
            ->getElementsInitialized();
          $build[$id]['data'] = [
            '#theme' => 'webform_codemirror',
            '#code' => $this
              ->buildElements($elements, $webform_submission, $options, 'text'),
          ];
          break;
        case 'table':
          $elements = $webform
            ->getElementsInitializedFlattenedAndHasValue();
          $build[$id]['data'] = $this
            ->buildTable($elements, $webform_submission, $options);
          break;
        default:
        case 'html':
          $elements = $webform
            ->getElementsInitialized();
          $build[$id]['data'] = $this
            ->buildElements($elements, $webform_submission, $options);
          break;
      }
    }
    parent::buildComponents($build, $entities, $displays, $view_mode);
  }

  /**
   * {@inheritdoc}
   */
  public function buildElements(array $elements, WebformSubmissionInterface $webform_submission, array $options = [], $format = 'html') {
    $build_method = 'build' . ucfirst($format);
    $build = [];
    foreach ($elements as $key => $element) {
      if (!WebformElementHelper::isElement($element, $key)) {
        continue;
      }

      /** @var \Drupal\webform\Plugin\WebformElementInterface $webform_element */
      $webform_element = $this->elementManager
        ->getElementInstance($element);

      // Replace tokens before building the element.
      $webform_element
        ->replaceTokens($element, $webform_submission);
      if ($build_element = $webform_element
        ->{$build_method}($element, $webform_submission, $options)) {
        $build[$key] = $build_element;
        if (!$this
          ->isElementVisible($element, $webform_submission, $options)) {
          $build[$key]['#access'] = FALSE;
        }
      }
    }
    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function buildTable(array $elements, WebformSubmissionInterface $webform_submission, array $options = []) {
    $rows = [];
    foreach ($elements as $key => $element) {
      if (!$this
        ->isElementVisible($element, $webform_submission, $options)) {
        continue;
      }

      /** @var \Drupal\webform\Plugin\WebformElementInterface $webform_element */
      $webform_element = $this->elementManager
        ->getElementInstance($element);

      // Replace tokens before building the element.
      $webform_element
        ->replaceTokens($element, $webform_submission);

      // Check if empty value is excluded.
      if ($webform_element
        ->isEmptyExcluded($element, $options) && !$webform_element
        ->getValue($element, $webform_submission, $options)) {
        continue;
      }
      $title = $element['#admin_title'] ?: $element['#title'] ?: '(' . $key . ')';

      // Note: Not displaying an empty message since empty values just render
      // an empty table cell.
      $html = $webform_element
        ->formatHtml($element, $webform_submission, $options);
      $rows[$key] = [
        [
          'header' => TRUE,
          'data' => $title,
        ],
        [
          'data' => is_string($html) ? [
            '#markup' => $html,
          ] : $html,
        ],
      ];
    }
    return [
      '#type' => 'table',
      '#rows' => $rows,
      '#attributes' => [
        'class' => [
          'webform-submission-table',
        ],
      ],
    ];
  }

  /**
   * Determines if an element is visible.
   *
   * @param array $element
   *   The element to check for visibility.
   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
   *   A webform submission.
   * @param array $options
   *   - excluded_elements: An array of elements to be excluded.
   *   - ignore_access: Flag to ignore private and/or access controls and always
   *     display the element.
   *   - email: Format element to be send via email.
   *
   * @return bool
   *   TRUE if the element is visible, otherwise FALSE.
   *
   * @see \Drupal\webform\WebformSubmissionConditionsValidatorInterface::isElementVisible
   * @see \Drupal\Core\Render\Element::isVisibleElement
   */
  protected function isElementVisible(array $element, WebformSubmissionInterface $webform_submission, array $options) {

    // Checked excluded elements.
    if (isset($element['#webform_key']) && isset($options['excluded_elements'][$element['#webform_key']])) {
      return FALSE;
    }

    // Checked excluded attachments, except from composite elements.
    // @see \Drupal\webform\Plugin\WebformElement\WebformCompositeBase::formatComposite
    if (!empty($options['exclude_attachments'])) {

      /** @var \Drupal\webform\Plugin\WebformElementInterface $webform_element */
      $webform_element = $this->elementManager
        ->getElementInstance($element, $webform_submission);
      if ($webform_element instanceof WebformElementAttachmentInterface && !$webform_element instanceof WebformElementCompositeInterface) {
        return FALSE;
      }
    }

    // Check if the element is conditionally hidden.
    if (!$this->conditionsValidator
      ->isElementVisible($element, $webform_submission)) {
      return FALSE;
    }

    // Check if ignore access is set.
    // This is used email handlers to include administrative elements in emails.
    if (!empty($options['ignore_access'])) {
      return TRUE;
    }

    // Check check the element's #access.
    if (isset($element['#access']) && ($element['#access'] instanceof AccessResultInterface && $element['#access']
      ->isForbidden() || $element['#access'] === FALSE)) {
      return FALSE;
    }

    // Finally, check the element's 'view' access.

    /** @var \Drupal\webform\Plugin\WebformElementInterface $webform_element */
    $webform_element = $this->elementManager
      ->getElementInstance($element, $webform_submission);
    return $webform_element
      ->checkAccessRules('view', $element) ? TRUE : FALSE;
  }

}

Classes

Namesort descending Description
WebformSubmissionViewBuilder Render controller for webform submissions.