0

I use the D8 core render service for generating markup that is indexed in an external search service. The indexing is happening on hook_entity_update, where I call my indexing service. My custom indexing service is then using the core render service for creating the markup.

Example with static service call:

// Get the render array for the teaser.
$viewBuilder = \Drupal::entityTypeManager()
  ->getViewBuilder($entity->getEntityTypeId());
$render_array_teaser = $viewBuilder->view($entity, 'teaser');   

// Generate the markup from the render_array.
$renderer = \Drupal::service('renderer');
$rendered_teaser = $renderer->renderPlain($render_array_teaser);
// When called in hook_entity_update $rendered teaser has a crappy
// default markup in it as a 'teaser' view mode and the correct twig 
// templates don't exist in the backend theme.

This works fine when called from drush. But when called from hook_entity_update() the renderer has the wrong theme context. As the node edit form that triggers the update uses the backend theme, the renderer gets also the backend theme as context instead of the default theme.

The renderer gets the current theme injected with the ThemeManager object. See core services:

renderer:
  class: Drupal\Core\Render\Renderer
  arguments: ['@controller_resolver', '@theme.manager','@plugin.manager.element_info', '@render_placeholder_generator', '@render_cache', '@request_stack', '%renderer.config%']

How can I initialize the service but provide my own version of the ThemeManager object?

There is a setter method on the ThemeManager object where I could easily set the right theme. But I need to hand this over to the renderer.

e.g.:

$my_theme_manager = \Drupal::service('theme.manager');
$my_theme_manager->setActiveTheme('my_frontend_theme');

// How to get the service with this alternative context?
// e.g. something like that.
$service = \Drupal::Service();
$service->setService('renderer');
$service->setArgument(['@theme_manager' => $my_theme_manager]);
$default_theme_renderer = $service->getService();

Or is there some way to alter the ThemeManager Object when it is initialized? Before it is injected into the render service? So I can set the correct theme in an event or alter hook?

I know that I can alter the service in general by implementing the ServiceModifierInterfacebut this will modify the container when it gets created as far as I know, and is not a way for manipulation during runtime.

1 Answer 1

3

The mailsystem module is doing exactly what you are looking for I think. It has a configuration option to select which theme should be used to render mail templates.

See MailsystemManager::mail()

// Switch the theme to the configured mail theme.
$mail_theme = $this->getMailTheme();
$current_active_theme = $this->themeManager->getActiveTheme();
if ($mail_theme && $mail_theme != $current_active_theme->getName()) {
  $this->themeManager->setActiveTheme($this->themeInitialization->initTheme($mail_theme));
}

try {
  $message = parent::mail($module, $key, $to, $langcode, $params, $reply, $send);
}
finally {
  // Revert the active theme, this is done inside a finally block so it is
  // executed even if an exception is thrown during sending a mail.
  if ($mail_theme != $current_active_theme->getName()) {
    $this->themeManager->setActiveTheme($current_active_theme);
  }
}
return $message;

}

You can't tell the renderer directly which theme to use. But, you can switch out the active theme before you call it an then switch it back (the try/finally is important, so that you don't end up with the wrong active theme in case of an exception).

The service names for the two used services is theme.manager and theme.initialization.

1
  • Thanks Berdir. I was nearly there. Was only missing that setActiveTheme is expecting an ActiveTheme Object and not the theme machine_name. I wonder that I didn't get an exception when I tried a string there.
    – marcusx
    Commented Apr 6, 2016 at 20:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.