mustache_templates-8.x-1.0-beta4/modules/mustache_views/src/MustacheViews.php
modules/mustache_views/src/MustacheViews.php
<?php
namespace Drupal\mustache_views;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\mustache\Helpers\Mustache;
use Drupal\mustache\Helpers\MustacheRenderTemplate;
use Drupal\views\ViewExecutable;
/**
* 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 = [];
$view = $query->getMetaData('view');
if (!($view instanceof ViewExecutable)) {
return;
}
$this->collectTemplates($query, $to_evaluate);
if (empty($to_evaluate)) {
return;
}
$bubbleable_metadata = BubbleableMetadata::createFromRenderArray($view->element);
$previous_cache_contexts = $bubbleable_metadata->getCacheContexts();
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);
});
$bubbleable_metadata
->addCacheableDependency(BubbleableMetadata::createFromRenderArray($build));
if (isset($build['#content'])) {
$trimmed = trim((string) $build['#content']);
if ($trimmed !== '') {
$text = $trimmed;
}
}
}
// @todo Resolve this to be cacheable by respecting cache contexts within
// \Drupal\views\Plugin\views\cache\CachePluginBase::generateResultsKey().
// @see https://www.drupal.org/project/mustache_templates/issues/3253881
if (array_diff($bubbleable_metadata->getCacheContexts(), $previous_cache_contexts)) {
$bubbleable_metadata->mergeCacheMaxAge(0);
}
$bubbleable_metadata->applyTo($view->element);
}
/**
* 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'];
}
}
}
}
}
