1

I'm currently using TWIG to manipulate variables that have been created in Drupal 8. For example, I have a template that contains the following logic:

{% if item.field_main_images[0] %}
  {% if item.field_main_images[0]['#item'].entity.uri.value != "" and item.field_main_images[0]['#item'].entity.uri.value is not empty %}
    {% set main_image_uri = item.field_main_images[0]['#item'].entity.uri.value %}
    {% set main_image_zoom = main_image_uri | image_style('item_zoom') %}
  {% endif %}
{% endif %}

and

{% set featured_content = '' %}
{% if item.field_item_specification.0['#text'] is not empty %}
  {% set featured_content = item.field_item_specification %}
{% endif %}

Am I missing something here because i'm getting caught in spending a lot of time figuring out the data structures of the objects and manipulating the logic within my TWIG templates. I've got a feeling that I should be doing this in either a preprocess function on the content type or by some other means.

How could I perform this same procedure using the drupal framework i.e. symphony to create/manipulate the variables before the use of a twig template.

Can anyone shed some light on this?

Thanks in advance.

1
  • You are manipulating render arrays built by field formatters. You probably put this code in Twig, because the core field formatters don't provide the configuration options you need. So you have to look in contrib or build custom field formatters. – 4k4 Dec 5 '17 at 7:28
1

You are right, this kind of code should be in your controller or in preprocess functions. You should generate a render array for each twig template, to be able to have a simple :

{{ image_with_zoom }}

In your twig file. Your controller could have something like :

  $renderArray = [];
  /* @var $item \Drupal\node\Entity\Node */
  if($item->field_main_images->count()){
    $image = File::load($item->field_main_images->target_id);
    $renderArray['image_with_zoom'] = [
      '#theme' => 'image_style',
      '#style_name' => '...',
      '#uri' => $image->getFileUri(),
      '#attributes' => [
        'data-zoom-url' =>  ImageStyle::load('item_zoom')->buildUrl($image->getFileUri())
      ]
    ];
  }

Have also a look at field formatters, it allow you to get your own controls for each field you wish to display. You can generate some skeleton with the drupal command :

$ drupal gpff

Have a look at documentation on this point, and the one in the drupal console. That's quiet important if you wish to reuse some display for a particular field as it looks like.

1

Disclaimer: This is going to be a bit "ranty"

I'm quite new to Drupal to, having the same issues, and my resumee is: That's an architectural flaw of Drupal itself and cannot be solved with a reasonable time budget.

For me it seems Drupal tries to provide a point-and-click interface to what would be a combination of view and controller in other systems ("view modes"). When you can't solve your problems using view modes (which happens at every of my projects), the clean, drupalesque solution would be creating a field formatter module (containing the logic), so you can keep using view modes and clean templates. As soon as you start doing logic in preprocessing or twigging, you often have to mess with render arrays, and render arrays are ... well ... not so super-intuitive.

My conclusion is: If you have got big budget, write field formatters. On a tight budget use preprocessing for fetching additional data and for more complex logic (e.g. cross-field-dependencies). Use Twig for simple logic and for small variations of the same data (use/extend/embed/...). If I find myself altering render arrays in Twig, I know that I need to refactor and switch to preprocessing.

Personally I would use template preprocessing for your first example, and keep the second in Twig.

1

I agree that this kind of logic should be handled in preprocessing, rather than within the TWIG templates. This keeps the templates simple and ensures themers being able to focus on theming without having to deal with too complex program logic (that might even break when you or the related modules rename fields or alter entities).

Fortunately, your ability to do your tweaks within TWIG templates shows, that field formatters/blocks/... are not rendering and returning static HTML (which unfortunately still happens far too often in modules migrated from older Drupal versions).

The output is rendered utilizing Drupal's theming registry.

This allows you to alter/extend this registry and use hook_theme_registry_alter() to add your own preprocessing to the templates within a custom module's .module file (the theme hook key 'the_theme_hook_to_extend' most often matches the template name with underscores instead of the dashes):

/**
 * Implements hook_theme_registry_alter().
 */
function MYMODULE_theme_registry_alter(&$theme_registry) {
  // Add custom preprocessing.
  if (isset($theme_registry['the_theme_hook_to_extend'])) {
    $theme_registry['the_theme_hook_to_extend']['preprocess functions'][] = 'MYMODULE_preprocess_for_the_theme_hook_to_extend';
  }
}

Then add the above defined preprocess function to your module to add your program logic:

/**
 * Custom preprocess for the_theme_hook_to_extend.
 *
 * Used to do some additional magic.
 *
 * @param array $variables
 *   Theme variables.
 */
function MYMODULE_preprocess_for_the_theme_hook_to_extend(array &$variables) {
  // Alter your variables accordingly, add additional
  // variables, or do whatever else preprocessing you
  // need.
}

I hope, this is the light you've been asking for.

EDIT:

The above example is a simple one that adds a preprocessing to the theme registry. You can actually use that hook for removing other module's preprocessing, or replace templates, and even controllers.

If you are looking for adding your own preprocessing only, you can simply utilize hook_preprocess_HOOK() in your module or theme to alter variables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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