You are here

class WebformTwigExtension in Webform 8.5

Same name and namespace in other branches
  1. 6.x src/Twig/WebformTwigExtension.php \Drupal\webform\Twig\WebformTwigExtension

Twig extension with some useful functions and filters.

Hierarchy

Expanded class hierarchy of WebformTwigExtension

9 files declare their use of WebformTwigExtension
EmailWebformHandler.php in src/Plugin/WebformHandler/EmailWebformHandler.php
WebformAttachmentTwig.php in modules/webform_attachment/src/Element/WebformAttachmentTwig.php
WebformAttachmentTwig.php in modules/webform_attachment/src/Plugin/WebformElement/WebformAttachmentTwig.php
WebformCodeMirror.php in src/Element/WebformCodeMirror.php
WebformComputedTwig.php in src/Element/WebformComputedTwig.php

... See full list

1 string reference to 'WebformTwigExtension'
webform.services.yml in ./webform.services.yml
webform.services.yml
1 service uses WebformTwigExtension
webform.twig_extension in ./webform.services.yml
Drupal\webform\Twig\WebformTwigExtension

File

src/Twig/WebformTwigExtension.php, line 18

Namespace

Drupal\webform\Twig
View source
class WebformTwigExtension extends \Twig_Extension {
  protected static $options = [
    'html' => 'webform_token_options_html',
    'email' => 'webform_token_options_email',
  ];

  /**
   * {@inheritdoc}
   */
  public function getFunctions() {
    return [
      new \Twig_SimpleFunction('webform_html_editor_check_markup', [
        $this,
        'webformHtmlEditorCheckMarkup',
      ]),
      new \Twig_SimpleFunction('webform_debug', [
        $this,
        'webformDebug',
      ]),
      new \Twig_SimpleFunction('webform_token', [
        $this,
        'webformToken',
      ]),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return 'webform';
  }

  /**
   * Runs HTML markup through (optional) text format.
   *
   * @param string $text
   *   The text to be filtered.
   * @param array $options
   *   HTML markup options.
   *
   * @return array
   *   Render array containing 'processed_text' or 'webform_html_editor_markup'.
   *
   * @see \Drupal\webform\Element\WebformHtmlEditor::checkMarkup
   */
  public function webformHtmlEditorCheckMarkup($text, array $options = []) {
    return WebformHtmlEditor::checkMarkup($text, $options);
  }

  /**
   * Debug data by outputting YAML.
   *
   * @param mixed $data
   *   Data to be outputted.
   *
   * @return string
   *   Data serialized to YAML.
   */
  public function webformDebug($data) {
    try {
      if (is_array($data)) {
        WebformElementHelper::convertRenderMarkupToStrings($data);
        return WebformYaml::encode($data);
      }
      else {
        return $data;
      }
    } catch (\Exception $exception) {
      return $exception
        ->getMessage();
    }
  }

  /**
   * Replace tokens in text.
   *
   * @param string|array $token
   *   A string of text that may contain tokens.
   * @param \Drupal\Core\Entity\EntityInterface|null $entity
   *   A Webform or Webform submission entity.
   * @param array $data
   *   (optional) An array of keyed objects.
   * @param array $options
   *   (optional) A keyed array of settings and flags to control the token
   *   replacement process.
   *
   * @return string|array
   *   Text or array with tokens replaced.
   *
   * @see \Drupal\Core\Utility\Token::replace
   */
  public function webformToken($token, EntityInterface $entity = NULL, array $data = [], array $options = []) {

    // Allow the webform_token function to be tested during validation without
    // a valid entity.
    if (!$entity) {
      return $token;
    }
    $original_token = $token;
    if (WebformLogicHelper::startRecursionTracking($token) === FALSE) {
      return '';
    }

    // Parse options included in the token.
    // @see \Drupal\webform\Twig\TwigExtension::renderTwigTemplate
    foreach (static::$options as $option_name => $option_setting) {
      if (strpos($token, ":{$option_setting}")) {
        $options[$option_name] = TRUE;
        $token = str_replace(":{$option_setting}", '', $token);
      }
    }

    // IMPORTANT: We are not injecting the WebformTokenManager to prevent
    // errors being thrown when updating the Webform.module.
    // ISSUE. This TwigExtension is loaded on every page load, even when a
    // website is in maintenance mode.
    // @see https://www.drupal.org/node/2907960

    /** @var \Drupal\webform\WebformTokenManagerInterface $token_manager */
    $token_manager = \Drupal::service('webform.token_manager');
    $value = $token_manager
      ->replace($token, $entity, $data, $options);
    if (WebformLogicHelper::stopRecursionTracking($original_token) === FALSE) {
      return '';
    }
    return WebformHtmlHelper::containsHtml($value) ? [
      '#markup' => $value,
      '#allowed_tags' => WebformXss::getAdminTagList(),
    ] : $value;
  }

  /****************************************************************************/

  // Token methods used by the 'WebformComputedTwig' and 'EmailWebformHandler'.
  //
  // @see \Drupal\webform\Plugin\WebformElement\WebformComputedTwig
  // @see \Drupal\webform\Plugin\WebformHandler\EmailWebformHandler

  /****************************************************************************/

  /**
   * Build reusable Twig help.
   *
   * @param array $variables
   *   An array of available variable names.
   *
   * @return array
   *   A renderable array container Twig help.
   */
  public static function buildTwigHelp(array $variables = []) {

    /** @var \Drupal\webform\WebformSubmissionStorageInterface $submission_storage */
    $submission_storage = \Drupal::entityTypeManager()
      ->getStorage('webform_submission');
    $field_definitions = $submission_storage
      ->getFieldDefinitions();

    // Bold all the passed variable names.
    foreach ($variables as $index => $item) {
      $variables[$index] = [
        '#markup' => $item,
        '#prefix' => '<strong>',
        '#suffix' => '</strong>',
      ];
    }
    $variables = array_merge($variables, [
      '{{ data.element_key }}',
      '{{ data[\'element_key\'] }}',
      '{{ data.element_key.delta }}',
      '{{ data[\'element_key\'][\'delta\'] }}',
      '{{ data.composite_element_key.subelement_key }}',
      '{{ data.composite_element_key.delta.subelement_key }}',
      '{{ original_data }}',
      '{{ elements }}',
      '{{ elements_flattened }}',
    ]);
    foreach (array_keys($field_definitions) as $field_name) {
      $variables[] = "{{ {$field_name} }}";
    }
    $variables = array_merge($variables, [
      '{{ webform }}',
      '{{ webform_submission }}',
    ]);
    $t_args = [
      ':twig_href' => 'https://twig.sensiolabs.org/',
      ':drupal_href' => 'https://www.drupal.org/docs/8/theming/twig',
    ];
    $output = [];
    $output[] = [
      '#markup' => '<p>' . t('Learn about <a href=":twig_href">Twig</a> and how it is used in <a href=":drupal_href">Drupal</a>.', $t_args) . '</p>',
    ];
    $output[] = [
      '#markup' => '<p>' . t("The following variables are available:") . '</p>',
    ];
    $output[] = [
      '#theme' => 'item_list',
      '#items' => $variables,
    ];
    $output[] = [
      '#markup' => '<p>' . t("You can also output tokens using the <code>webform_token()</code> function.") . '</p>',
    ];
    $output[] = [
      '#markup' => "<pre>{{ webform_token('[webform_submission:values:element_value]', webform_submission, [], options) }}</pre>",
    ];
    $output[] = [
      '#markup' => '<p>' . t("You can debug data using the <code>webform_debug()</code> function.") . '</p>',
    ];
    $output[] = [
      '#markup' => "<pre>{{ webform_debug(data) }}</pre>",
    ];
    if (\Drupal::currentUser()
      ->hasPermission('administer modules') && !\Drupal::moduleHandler()
      ->moduleExists('twig_tweak')) {
      $t_args = [
        ':module_href' => 'https://www.drupal.org/project/twig_tweak',
        ':documentation_href' => 'https://www.drupal.org/docs/8/modules/twig-tweak/cheat-sheet-8x-2x',
      ];
      $output[] = [
        '#type' => 'webform_message',
        '#message_type' => 'info',
        '#message_message' => t('Install the <a href=":module_href">Twig tweak</a> module, which provides a Twig extension with some <a href=":documentation_href">useful functions and filters</a> that can improve development experience.', $t_args),
        '#message_close' => TRUE,
        '#storage' => WebformMessage::STORAGE_SESSION,
      ];
    }
    return [
      '#type' => 'details',
      '#title' => t('Help using Twig'),
      'description' => $output,
    ];
  }

  /**
   * Render a Twig template with a webform submission.
   *
   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
   *   A webform submission.
   * @param string $template
   *   A inline Twig template.
   * @param array $options
   *   (optional) Template and token options.
   * @param array $context
   *   (optional) Context to be passed to inline Twig template.
   *
   * @return string
   *   The fully rendered Twig template.
   *
   * @see \Drupal\webform\Element\WebformComputedTwig::computeValue
   * @see \Drupal\webform\Plugin\WebformHandler\EmailWebformHandler::getMessage
   */
  public static function renderTwigTemplate(WebformSubmissionInterface $webform_submission, $template, array $options = [], array $context = []) {
    try {
      $build = static::buildTwigTemplate($webform_submission, $template, $options, $context);
      return \Drupal::service('renderer')
        ->renderPlain($build);
    } catch (\Exception $exception) {
      if ($webform_submission
        ->getWebform()
        ->access('update')) {
        \Drupal::messenger()
          ->addError($exception
          ->getMessage());
      }
      \Drupal::logger('webform')
        ->error($exception
        ->getMessage());
      return '';
    }
  }

  /**
   * Build a Twig template with a webform submission.
   *
   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
   *   A webform submission.
   * @param string $template
   *   A inline Twig template.
   * @param array $options
   *   (optional) Template, token options, and context.
   * @param array $context
   *   (optional) Context to be passed to inline Twig template.
   *
   * @return array
   *   A renderable containing an inline twig template.
   */
  public static function buildTwigTemplate(WebformSubmissionInterface $webform_submission, $template, array $options = [], array $context = []) {
    $options += [
      'html' => FALSE,
      'email' => FALSE,
    ];

    // Include 'html' and 'email' options in the token.
    // @see \Drupal\webform\Twig\TwigExtension::renderTwigTemplate
    foreach (static::$options as $option_name => $option_setting) {
      if ($options[$option_name]) {
        $template = preg_replace('/\\[(webform_submission:values:?[^]]*)\\]/', '[\\1:' . $option_setting . ']', $template);
      }
    }

    // If the template does NOT use the webform_token() function, but contains
    // simple tokens, convert the simple tokens to use
    // the webform_token() function.
    if (strpos($template, 'webform_token(') === FALSE && strpos($template, '[webform') !== FALSE) {
      $template = preg_replace('#([^"\']|^)(\\[[^]]+\\])([^"\']|$)#', '\\1{{ webform_token(\'\\2\', webform_submission) }}\\3', $template);
    }
    $context += [
      'webform_submission' => $webform_submission,
      'webform' => $webform_submission
        ->getWebform(),
      'elements' => $webform_submission
        ->getWebform()
        ->getElementsDecoded(),
      'elements_flattened' => $webform_submission
        ->getWebform()
        ->getElementsDecodedAndFlattened(),
      'options' => $options,
      'original_data' => $webform_submission
        ->getOriginalData(),
    ] + $webform_submission
      ->toArray(TRUE);
    return [
      '#type' => 'inline_template',
      '#template' => $template,
      '#context' => $context,
    ];
  }

  /**
   * Determine if the current user can edit Twig templates.
   *
   * @return bool
   *   TRUE if the current user can edit Twig templates.
   */
  public static function hasEditTwigAccess() {
    return \Drupal::currentUser()
      ->hasPermission('edit webform twig') || \Drupal::currentUser()
      ->hasPermission('administer webform');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
WebformTwigExtension::$options protected static property
WebformTwigExtension::buildTwigHelp public static function Build reusable Twig help.
WebformTwigExtension::buildTwigTemplate public static function Build a Twig template with a webform submission.
WebformTwigExtension::getFunctions public function
WebformTwigExtension::getName public function
WebformTwigExtension::hasEditTwigAccess public static function Determine if the current user can edit Twig templates.
WebformTwigExtension::renderTwigTemplate public static function Render a Twig template with a webform submission.
WebformTwigExtension::webformDebug public function Debug data by outputting YAML.
WebformTwigExtension::webformHtmlEditorCheckMarkup public function Runs HTML markup through (optional) text format.
WebformTwigExtension::webformToken public function Replace tokens in text.