0

I have the following content types (for a simple LMS) defined:

  • Lessons, for which there are rather complex rules for handling view access.
  • Courses, which contain entity references to one or more Lessons.

Now, in the Twig template for rendering a Course node, I am trying to create a "table of contents" (a list of Lessons), using the following snippet:

<nav id='toc_lessons' class="list-group">
  {% for key, lesson in content.field_lessons %}
    {% if lesson['#node'].title.value|render|striptags|trim %}

        <a class="list-group-item list-group-item-action
           href="{{ url('<current>') }}/?lesson={{ lesson['#node'].nid.value }}">
          {{ lesson['#node'].title.value }}
          {{ (*****) ? '<span class="label">LOCKED</span>' }}
        </a>

    {% endif %}
  {% endfor %}
</nav>

This works well. However, the problem with this code is the line that I marked with (*****): I would like to do a simple access check, i.e. I would like to check, if the user is allowed to view the Lesson. If not, the label "LOCKED" should be added.

In my implementation of function THEME_preprocess_node I have already defined such a check that is called whenever a Lesson is rendered:

function THEME_preprocess_node(&$variables) {
  ...
  $node = $variables['elements']['#node'];
  $variables['viewaccess'] = $node->access('view');
  ...
}

But can I call the preprocessing function for a Lesson from within the Course template to receive the variable viewaccess?

Another idea would be to modify the above snippet as follows:

<nav id='toc_lessons' class="list-group">
  {% for key, lesson in content.field_lessons %}
    {% if lesson['#node'].title.value|render|striptags|trim %}

        {{ bamboo_render_entity('node', lesson['#node'].nid.value, 'toc_entry') }}

    {% endif %}
  {% endfor %}
</nav>

so, I am now rendering the Lesson using Bamboo Twig and the output <a>...</a> is fully handled by the Lesson template, which works fine. The problem now is that a Lesson that the user does not have view access for, is not rendered at all.

Now, I'm stuck. Can anybody offer any ideas?

Any help would be much appreciated.

1 Answer 1

3

You're pretty close. I think there are a couple of approaches to this. This is what I would do

preprocess the lessons entity reference field for the courses bundle, iterate through the values, check the access, set a variable with the access value for each item. Then in field--field-lessons.twig.html, render the field if the access value is true.

<?php
//the name of your lessons entity reference field on courses
function THEME_preprocess_field__field_lessons(&$variables) {

  if($variables['element']['#bundle'] == 'courses') {
    $account = \Drupal::currentUser();
    $ent_refs = $variables['element']['#items']->referencedEntities();

    foreach ($ent_refs as $key => $ent_ref) {
      $check = $ent_ref->access('view', $account);
      $variables['items'][$key]['my_access'] = FALSE;

      if ($check) {
        $variables['items'][$key]['my_access'] = TRUE;
      }
    }

  }
}

then in field--field-lessons.twig.html

...
{% for item in items %}
    {% if item.my_access == TRUE %}
      I'm Unlocked: {{ item.content }}
    {% else %}
      I'm locked :(
    {% endif %}
  {% endfor %}
...
5
  • Ah, I hadn't thought of preprocessing the field. That sounds like a good idea, thank you very much. Will check and report back.
    – Marcus C.
    Oct 25, 2018 at 8:16
  • Thanks again for your help. I tried your suggestion and it really does seem to work (i.e. I'm able to use the variable added in THEME_preprocess_field to output a "LOCKED" label)... until I also try to output, say, the title of the locked item: Using {{ item.content['#node'].title.value }} in field--field-lessons.twig.html for a locked lesson prints out nothing (and, even more surprisingly, makes the for loop immediately jump to the next item). Any idea, why this happens? Can't I access and print a field's content, if the current user doesn't have view access to the node? Seems weird.
    – Marcus C.
    Oct 25, 2018 at 13:39
  • 1
    Hm, seems like you should be able to. Try accessing the title this way in twig: {{ item.content['#title']|raw }} Oct 25, 2018 at 14:03
  • Thanks again. I ended up simply storing the title (and a few other fields) in variables (within THEME_preprocess_field) so that I can access them in field--field-lessons.twig.html. Probably not the easiest solution and I'm still unsure, as to why that is necessary in the first place. But that's stuff for another question... :) Thanks again for your help.
    – Marcus C.
    Oct 25, 2018 at 17:32
  • @MattCampbell It is bad security practice to use the |raw filter. As when you use this filter Twigs auto escaping is no longer used. See How do I get the raw field value in a twig template? for proper/safe way to do it.
    – No Sssweat
    Oct 25, 2018 at 17:41

Your Answer

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

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