0

Is this considered a good practice for rendering a Twig template and loading a CSS file from a controller?

DefaultController.php

namespace Drupal\acme\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Template\TwigEnvironment;

class DefaultController extends ControllerBase implements ContainerInjectionInterface 
{
  /**
  * @var Drupal\Core\Template\TwigEnvironment
  */
  protected $twig;

  public function __construct(TwigEnvironment $twig)
  {
    $this->twig = $twig;
  }

  public static function create(ContainerInterface $container)
  {
    return new static(
      $container->get('twig')
    );
  }

  /**
   * hello
   * @param  string $name
   * @return string
   */
  public function hello($name) 
  {

    $template = $this->twig->loadTemplate(
      drupal_get_path('module', 'acme') . '/templates/hello.html.twig'
    );

    $markup = [
      '#markup' => $template->render([ 'name' => $name ]),
      '#attached' => [ 'css' => [
          drupal_get_path('module', 'acme') . '/assets/css/acme.css'
        ]
      ]
    ];

    return drupal_render($markup);
  }
}

acme.routing.yml

acme_hello:
  path: '/acme/hello/{name}'
  defaults:
    _content: '\Drupal\acme\Controller\DefaultController::hello'
    _title: 'acme Title'
  requirements:
    _permission: 'access content'

hello.html.twig

<div class="acme-hello-text">
  <h1>Hello {{ name }}!</h1>
</div>
4
  • Welcome to Drupal Answers! About what are you concerned? Also, "a good example" is rather subjective; you should explain what is a good example for you.
    – apaderno
    May 6, 2014 at 18:48
  • I was asking if this is considered a good practice, is any way I can edit the question ?
    – jmolivas
    May 6, 2014 at 18:54
  • 2
    Why would you want to call twig manually? You should define your template with hook_theme(), just like you did in 7.x and then use #theme, just like in Drupal 7, you don't need to bother about using twig directly.
    – Berdir
    May 6, 2014 at 21:36
  • Btw. You should use \Drupal::service('renderer')->renderRoot() instead of deprecated drupal_render().
    – kenorb
    Aug 5, 2017 at 11:02

2 Answers 2

5

As far as I understand, the controller should just contain the following code.

class DefaultController implements ControllerInterface {
  public function hello($name) {
    $twig = $this->container->get('twig');
    $path = $this->templateDir . 'hello.html.twig';
    $template = $twig->loadTemplate($path);

    return [
      '#markup' => $template->render(['name' => $name]),
    ];
  }
}

See also Drupal 8: An Introduction to the New Production.

I still have to find a reason to do this, thought. hook_theme() is still supported by Drupal 8, and it doesn't seem it is getting deprecated, at this time. The only difference is that in Drupal 8, theme() has been renamed _theme(); as such, it should not be called directly.
Since you are asking if your code is considered good practice, I would say no: You should do as you did with Drupal 7, defining a theme function in hook_theme() that uses a template. Then return markup similar to the following one in your controller method.

[
  '#theme' => $your_theme_function,
  '#name' => $name,
];

Replace $your_theme_function with the theme function ID, and #name with the array index used for 'variables'.
Actually, there is a difference between Drupal 7 and Drupal 8: While Drupal 7 allows you to attach JavaScript and CSS, Drupal 8 allows you to attach just libraries, which are a set of JavaScript and CSS files with dependencies.

0
3

I refactored my code as follow, removing code from the controller class and updating the method hello

DefaultController.php


namespace Drupal\acme\Controller;

use Drupal\Core\Controller\ControllerBase;

class DefaultController extends ControllerBase 
{

  /**
   * hello
   * @param  string $name
   * @return string
   */
    public function hello($name) 
  {
    return [
      '#theme' => 'hello_page',
      '#name' => $name,
      '#attached' => [ 
        'css' => [
          drupal_get_path('module', 'acme') . '/assets/css/acme.css'
        ]
      ]
    ];
  }
}

And also adding a new function to

acme.module


  function acme_theme() {
    $theme['hello_page'] = [
      'variables' => ['name' => NULL],
      'template' => 'hello'
    ];

    return $theme;
  }

If interested you can see a gist containing all of the files and code here https://gist.github.com/jmolivas/d29065493a91f16f35b2

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.