Commit 312314c9 authored by mxh's avatar mxh
Browse files

Issue #3253779 by mxh: Views integration

parent c4d13a80
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ namespace Drupal\mustache_token;
use Drupal\Core\Utility\Token;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\mustache\Helpers\Mustache;
use Drupal\mustache\Helpers\MustacheRenderTemplate;
use Drupal\mustache\Render\Markup;

@@ -41,7 +42,7 @@ trait MustacheTokenDecoratorTrait {
   * {@inheritdoc}
   */
  public function replace($text, array $data = [], array $options = [], BubbleableMetadata $bubbleable_metadata = NULL) {
    if (empty($text) || strpos($text, '{{') === FALSE) {
    if (empty($text) || !Mustache::containsSyntax($text)) {
      // When no Mustache template syntax is included, then there is nothing to
      // do for this decorator.
      return $this->token->replace($text, $data, $options, $bubbleable_metadata);
+8 −0
Original line number Diff line number Diff line
type: module
name: 'Mustache Logic-less Views'
description: 'Enable users to write Mustache template syntax in Views.'
core_version_requirement: ^9
package: Other
dependencies:
  - mustache_templates:mustache
  - drupal:views
+18 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * The mustache_views module file.
 */

use Drupal\Core\Database\Query\AlterableInterface;

/**
 * Implements hook_query_TAG_alter().
 *
 * This is the hook_query_alter() for queries tagged by Views and is used to
 * evaluate any input that contains Mustache template syntax.
 */
function mustache_views_query_views_alter(AlterableInterface $query) {
  \Drupal::service('mustache.views')->alterQuery($query);
}
+4 −0
Original line number Diff line number Diff line
services:
  mustache.views:
    class: Drupal\mustache_views\MustacheViews
    arguments: ['@renderer']
+132 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\mustache_views;

use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\mustache\Helpers\Mustache;
use Drupal\mustache\Helpers\MustacheRenderTemplate;

/**
 * Service for integration of Mustache templates in Views.
 */
class MustacheViews {

  /**
   * The renderer.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * The MustacheViews constructor.
   *
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   */
  public function __construct(RendererInterface $renderer) {
    $this->renderer = $renderer;
  }

  /**
   * Query alteration that evaluates any Mustache template syntax.
   *
   * @param \Drupal\Core\Database\Query\AlterableInterface $query
   *   A Query object describing the composite parts of a SQL query.
   */
  public function alterQuery(AlterableInterface $query) {
    $to_evaluate = [];
    $this->collectTemplates($query, $to_evaluate);
    foreach ($to_evaluate as &$text) {
      $template = MustacheRenderTemplate::build(hash('md4', $text), $text)
        ->withTokens();
      $build = $template->toRenderArray();
      $this->renderer->executeInRenderContext(new RenderContext(), function () use (&$build) {
        $this->renderer->render($build);
      });
      if (isset($build['#content'])) {
        $trimmed = trim((string) $build['#content']);
        if ($trimmed !== '') {
          $text = $trimmed;
        }
      }
    }
  }

  /**
   * Collects templates from the given query.
   *
   * @param \Drupal\Core\Database\Query\AlterableInterface $query
   *   A Query object describing the composite parts of a SQL query.
   * @param array &$to_evaluate
   *   A list of already collected templates to evaluate.
   */
  protected function collectTemplates(AlterableInterface $query, array &$to_evaluate) {
    /** @var \Drupal\Core\Database\Query\Select $query */
    $tables = &$query->getTables();
    $conditions = &$query->conditions();

    foreach ($tables as $table_name => $table_metadata) {
      if (empty($table_metadata['arguments'])) {
        continue;
      }
      foreach ($table_metadata['arguments'] as $replacement_key => $value) {
        if (is_array($value)) {
          foreach ($value as $sub_key => $sub_value) {
            if (Mustache::containsSyntax($sub_value) || Mustache::containsToken($sub_value)) {
              $to_evaluate[] = &$tables[$table_name]['arguments'][$replacement_key][$sub_key];
            }
          }
        }
        elseif (Mustache::containsSyntax($value) || Mustache::containsToken($value)) {
          $to_evaluate[] = &$tables[$table_name]['arguments'][$replacement_key];
        }
      }
    }

    $this->collectFromConditions($query, $conditions, $to_evaluate);
  }

  /**
   * Sub-method to collect templates from conditions.
   *
   * @param \Drupal\Core\Database\Query\AlterableInterface $query
   *   A Query object describing the composite parts of a SQL query.
   * @param mixed &$conditions
   *   The conditions.
   * @param array &$to_evaluate
   *   A list of already collected templates to evaluate.
   */
  protected function collectFromConditions(AlterableInterface $query, &$conditions, array &$to_evaluate) {
    foreach ($conditions as $condition_id => &$condition) {
      if (!is_numeric($condition_id)) {
        continue;
      }
      if (is_string($condition['field']) && (Mustache::containsSyntax($condition['field']) || Mustache::containsToken($condition['field']))) {
        $to_evaluate[] = &$condition['field'];
      }
      elseif (is_object($condition['field'])) {
        $sub_conditions = &$condition['field']->conditions();
        $this->collectFromConditions($query, $sub_conditions, $to_evaluate);
      }
      if (is_object($condition['value'])) {
        $this->collectTemplates($condition['value'], $to_evaluate);
      }
      elseif (isset($condition['value'])) {
        if (is_array($condition['value'])) {
          foreach ($condition['value'] as $key => $value) {
            if (is_string($value) && (Mustache::containsSyntax($value) || Mustache::containsToken($value))) {
              $to_evaluate[] = &$condition['value'][$key];
            }
          }
        }
        elseif (is_string($condition['value']) && (Mustache::containsSyntax($condition['value']) || Mustache::containsToken($condition['value']))) {
          $to_evaluate[] = &$condition['value'];
        }
      }
    }
  }

}
Loading