1

All-- I'm trying to wrap my head around Drupal 8 development, and I'm trying to create a very simple field formatter. It's being applied to a multi-file field, and I'm just trying to display information for each file uploaded to a custom content type that uses this field.

But-- I'm having issues figuring out exactly how to properly pass data from my PHP files to my Twig template. The code and Twig template below are displaying info about the two files uploaded to a page just fine, but as you can see, I'm not looping through an array of items; I'm just inserting the variable names for some metadata I'm trying to display for some file objects, yet it's looping through and displaying the info for each file uploaded to the page even though I'm not doing a Twig loop. Also-- if I add HTML above or below the Twig template placeholders ({{uri}} and {{filename}}), the HTML is being duplicated for each file that has been uploaded to the page.

So long story short: how should I massage my code to pass data to Twig such that I can loop through it with a Twig loop (e.g., {% for item in items %}) and also prevent any additional markup in the Twig template from being duplicated?

NOTE: here is the original viewElements() function that I was using, and that was causing my issue; all the code after this block is the final code that actually works:

  public function viewElements(FieldItemListInterface $items, $langcode) {
    $element = array();
    foreach ($items as $delta => $item) {
    // Render each element as markup.
      $element[$delta] = array(
      '#items' => array(
      'uri' => file_create_url($item->entity->get('uri')->value),
      'filename' => $item->entity->get('filename')->value,
      '#theme' => 'video_file_display',
    );
   }
   return $element;
 }

From FieldFormatter PHP file:

public function viewElements(FieldItemListInterface $items, $langcode) {
$element[0] = array(
  '#theme' => 'video_file_display',
);
foreach ($items as $delta => $item) {
 $element[0]['#items'][] = array(
    'uri' => file_create_url($item->entity->get('uri')->value),
    'filename' => $item->entity->get('filename')->value,
  );
}
return $element;
}

From .module file (hook_theme):

function field_formatter_test_theme(){
  return array(
    'video_file_display' => array(
      'variables' => array(
        'items' => array(
          'uri' => NULL, 'filename' => NULL),
        ),
      'template' => 'video-file-display',
    ),
  );
}

Twig template:

<h3>Here is my page</h3>
{% for item in items %}
  {{item.uri}}<br/>
  {{item.filename}}
{% endfor %}

{{ kint() }}

Sample page output:

Here is my page
Twig context array(15)

(and examining the kint output shows null values for 'uri' and 'filename')

2

You define N #theme render arrays, if you want to be able to control the output in a single template, you need to define only one #theme element and pass it either two array of values or an array of arrays with a uri and filename key each.

$element[0] = array(
  '#theme' => 'video_file_display',
);
foreach ($items as $delta => $item) {
  $element[0]['#items'][] = array(
    'uri' => file_create_url($item->entity->get('uri')->value),
    'filename' => $item->entity->get('filename')->value,
  );
}
  • So how would I define a #theme element outside the loop and pass it an array? – Bryan Green May 19 '17 at 21:57
  • nothing special, only trick is to set it in delta 0 as drupal excepts things to be keyed by deltas. added an example – Berdir May 19 '17 at 22:38
  • Thank you for the example code! Is there anything I need to do to my hook_theme function? I'm using kint to examine the Twig variables, and now 'uri' and 'filename' are both null. I thought modifying the 'variables' assignment to ...'variables' => array('items' => array('uri' => NULL, 'filename' => NULL),)..... would do the trick, but no such luck. I've changed the code above to reflect the new template I'm trying... – Bryan Green May 19 '17 at 23:02
  • I've edited all the above code to reflect what I'm currently trying. – Bryan Green May 19 '17 at 23:16
  • OK, my bad-- I hadn't cleared the Twig cache-- your example code is exactly what I needed. Thanks! – Bryan Green May 20 '17 at 1:22

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.