Rendering content entities

Now, let's see what we can do with an entity to render it on the page. In doing so, we will stick to the existing view modes and try not to break it up into pieces for rendering in a custom template through our own theme hook. If you want to do that, you can. You should have all the knowledge for that already:

Instead, we will rely on the entity's default building methodology that allows us to render it according to the display mode configured in the UI, so, for example, as a teaser or as the full display mode. As always, we will continue with the Node as an example.

The first thing we need to do is get our hands on the view builder handler of the entity type. Remember this from the entity type plugin definition? Just like the storage handler, we can request it from the EntityTypeManager:

/** @var \Drupal\node\NodeViewBuilder $builder */
$builder = \Drupal::entityTypeManager()->getViewBuilder('node');

Now that we have that, the simplest way of turning our entity into a render array is to use the view() method:

$build = $builder->view($node);  

By default, this will use the full view mode, but we can pass a second parameter and specify another, such as teaser or whatever we have configured. A third optional parameter is the langcode of the translation (if we have it) we want to render in.

The $build variable is now a render array that uses the node theme hook defined by the Node module. You will notice also a #pre_render theme property that specifies a callable to be run before the rendering of this array. That is actually a reference back to the NodeViewBuilder (the node entity type view builder) which is responsible for preparing all the field values and all sorts of other processing we are not going to cover now. But the node.twig.html template file, preprocessed by the *_preprocess_node() preprocessors, also plays a big role in providing some extra variables to be used or rendered in the template.

If we want, we can also build render arrays for multiple entities at once:

$build = $builder->viewMultiple($node); 

This will still return a render array that contains multiple children for each entity being rendered. The #pre_render property I mentioned earlier, however, will stay at the top level and, this time, be responsible for building multiple entities.

Essentially, it is that simple to get from loading an entity to turning it into a render array. You have many different places where you can take control over the output. As I said, you can write your own theme hook and break up the entity into variables. You can also implement the preprocessor for its default theme functions and change some variables in there. You can even change the theme hook used and append a suggestion to it and then take it from there, as we saw in the chapter on theming:

$build = $builder->view($node);
$build['#theme'] = $build['#theme'] . '__my_suggestion';

Another important way in which we can control the output is by implementing a hook that gets fired when the entity is being built for rendering: hook_entity_view() or hook_ENTITY_TYPE_view(). So, let's see an example by which we want to append a disclaimer message at the bottom of all our Node entities when they are displayed in their full view mode. We can do something like this:

function module_name_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) { 
  if ($entity->getEntityTypeId() == 'node' && $view_mode == 'full') { 
    $build['disclaimer'] = [ 
      '#markup' => t('The content provided is for general information purposes only.'), 
      '#weight' => 100 
    ]; 
  } 
} 

The three important arguments we work with are the $build array passed by reference, and which contains the render array for the entire entity, the $entity object itself, and the $view_mode the latter is being rendered in. So, all we have to do is add our own render bits inside the $build array. As a bonus, we try to ensure that the message gets printed at the bottom by using the #weight property on the render array.