Commit fafd7148 authored by Mateu Aguiló Bosch's avatar Mateu Aguiló Bosch Committed by Mateu Aguiló Bosch
Browse files

Issue #3300563 by e0ipso: Add token replacements

parent 8bf6f425
Loading
Loading
Loading
Loading
+82 −12
Original line number Diff line number Diff line
@@ -5,14 +5,19 @@ namespace Drupal\cl_block\Plugin\Block;
use Drupal\cl_components\Component\Component;
use Drupal\cl_components\Component\ComponentDiscovery;
use Drupal\cl_components\Exception\ComponentNotFoundException;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Utility\Token;
use Psr\Log\LoggerInterface;
use SchemaForms\Drupal\FormGeneratorDrupal;
use Shaper\Transformation\TransformationInterface;
use Shaper\Util\Context;
use Symfony\Component\DependencyInjection\ContainerInterface;

@@ -22,6 +27,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 * @Block(
 *   id = "cl_component_block",
 *   deriver = "\Drupal\cl_block\Plugin\Derivative\ComponentBlockDeriver",
 *   context_definitions = {
 *     "language" = @ContextDefinition("language", required = FALSE, label = @Translation("Language")),
 *     "node" = @ContextDefinition("entity:node", required = FALSE,
 *       label = @Translation("Node")),
 *     "user" = @ContextDefinition("entity:user", required = FALSE,
 *       label = @Translation("User Context"), constraints = { "NotNull" = {} },
 *     ),
 *   }
 * )
 *
 * @internal
@@ -46,9 +59,9 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
  /**
   * The form generator from schema.
   *
   * @var \SchemaForms\Drupal\FormGeneratorDrupal
   * @var \Shaper\Transformation\TransformationInterface
   */
  protected FormGeneratorDrupal $formGenerator;
  protected TransformationInterface $formGenerator;

  /**
   * The component
@@ -64,12 +77,17 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
   */
  protected LoggerInterface $logger;

  /**
   * @var \Drupal\Core\Utility\Token
   */
  protected Token $token;

  /**
   * Does the site support inject.
   *
   * @var bool
   */
  protected $supportsInject = FALSE;
  protected bool $supportsInject = FALSE;

  /**
   * Constructs a new FieldBlock.
@@ -84,6 +102,10 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
   *   The component discovery.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   * @param \Shaper\Transformation\TransformationInterface $form_generator
   *   The form generator.
   * @param \Drupal\Core\Utility\Token $token
   *   The token replacement service.
   * @param bool $supports_inject
   *   TRUE if the site supports the inject syntax.
   */
@@ -93,12 +115,14 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
    $plugin_definition,
    ComponentDiscovery $component_discovery,
    LoggerInterface $logger,
    FormGeneratorDrupal $form_generator,
    TransformationInterface $form_generator,
    Token $token,
    bool $supports_inject
  ) {
    $this->logger = $logger;
    $this->componentDiscovery = $component_discovery;
    $this->formGenerator = $form_generator;
    $this->token = $token;

    // Get the entity type and field name from the plugin ID.
    [, $component_name] = explode(static::DERIVATIVE_SEPARATOR, $plugin_id, 4);
@@ -119,6 +143,7 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
      $container->get(ComponentDiscovery::class),
      $container->get('logger.channel.cl_block'),
      $container->get('cl_block.form_generator'),
      $container->get('token'),
      $container->get('module_handler')->moduleExists('cl_inject')
    );
  }
@@ -132,17 +157,21 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
    $twig_blocks = $config['component']['twig_blocks'] ?? [];
    $variant = $config['component']['variant'] ?? NULL;
    $component = $this->getComponent();
    $bubbleable_metadata = new BubbleableMetadata();
    $template = $this->generateComponentTemplate(
      $component,
      $variant,
      $twig_blocks,
      $context
      $context,
      $bubbleable_metadata
    );
    return [
    $build = [
      '#type' => 'inline_template',
      '#template' => $template,
      '#context' => $context,
    ];
    $bubbleable_metadata->applyTo($build);
    return $build;
  }

  /**
@@ -213,7 +242,12 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
      ],
    ];

    try {
      $component = $this->getComponent();
    }
    catch (ComponentNotFoundException $e) {
      return $form;
    }
    // Here is where we derive the form from the metadata.
    $metadata = $component->getMetadata();
    $schemas = $metadata->getSchemas();
@@ -238,7 +272,10 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
      '#suffix' => '</div>',
      '#weight' => 5,
    ];

    $form['tree'] = [
      '#theme' => 'token_tree_link',
      '#token_types' => ['node', 'user'],
    ];
    return $form;
  }

@@ -385,23 +422,56 @@ class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterfac
   *
   * @throws \Drupal\cl_components\Exception\TemplateNotFoundException
   */
  private function generateComponentTemplate(Component $component, string $variant, array $twig_blocks, array $context): string {
  private function generateComponentTemplate(Component $component, string $variant, array $twig_blocks, array $context, RefinableCacheableDependencyInterface $bubbleable_metadata): string {
    $token_data = array_filter($this->getContextValues());
    $metadata = $component->getMetadata();
    $component_path = $metadata->getPath();
    $template_name = $component->getTemplateName($variant);
    $template_path = $component_path . DIRECTORY_SEPARATOR . $template_name;
    $template = '{# This template was dynamically generated by cl_block #}' . PHP_EOL;
    // Replace possible tokens in the context mapping.
    $context = array_map(
      fn($item) => $this->token->replacePlain(
        $item,
        $token_data,
        ['clear' => TRUE],
        $bubbleable_metadata
      ),
      $context
    );
    $template .= empty($context)
      ? sprintf('{%% embed \'%s\' %%}', $template_path)
      : sprintf('{%% embed \'%s\' with %s %%}', $template_path, Json::encode($context));
    $template .= PHP_EOL;
    $options = ['clear' => TRUE];
    try {
      // If there is a language in the context of the block, use it.
      $language = $this->getContextValue('language');
      if ($language instanceof LanguageInterface) {
        $options['langcode'] = $language->getId();
      }
    }
    catch (ContextException $e) {
      // Intentionally left blank.
    }
    foreach ($twig_blocks as $block_name => $block_value) {
      $bl_val = $this->token->replace(
        $block_value['value'],
        $token_data,
        $options,
        $bubbleable_metadata
      );
      $block_build = [
        '#type' => 'processed_text',
        '#text' => $block_value['value'],
        '#text' => $bl_val,
        '#format' => is_array($block_value) ? $block_value['format'] : 'full_html_with_twig',
      ];
      try {
        $value = \Drupal::service('renderer')->render($block_build);
      }
      catch (\Exception $e) {
        $value = $bl_val;
      }
      $template .= "  {% block $block_name %}" . PHP_EOL
        . "    $value" . PHP_EOL
        . "  {% endblock %}" . PHP_EOL;