Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

Originally, most routing controllers implements "ControllerInterface", which leads to boilerplate code for even a simple method inside the controller. The main reason is all these controllers need to inject dependency objects(mostly, Drupal services) relying on some services.yml, no matter it's simple or complex.

See the simple TaxonomyController before this change:

<?php
/**
* @file
* Contains \Drupal\taxonomy\Controller\TaxonomyController.
*/
namespace Drupal\taxonomy\Controller;
use
Drupal\Core\Controller\ContainerInjectionInterface;
use
Drupal\Core\Entity\EntityManagerInterface;
use
Drupal\Core\Extension\ModuleHandlerInterface;
use
Drupal\taxonomy\TermStorageControllerInterface;
use
Drupal\taxonomy\VocabularyInterface;
use
Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides route responses for taxonomy.module.
*/
class TaxonomyController implements ContainerInjectionInterface {
 
/**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
 
protected $moduleHandler;
 
/**
   * The entity manager.
   *
   * @var \Drupal\Core\Entity\EntityManagerInterface
   */
 
protected $entityManager;
 
/**
   * The taxonomy term storage.
   *
   * @var \Drupal\taxonomy\TermStorageControllerInterface
   */
 
protected $termStorage;
 
/**
   * Constructs a new TaxonomyController.
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
   *   The entity manager.
   * @param \Drupal\taxonomy\TermStorageControllerInterface $term_storage
   *   The taxonomy term storage.
   */
 
public function __construct(ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, TermStorageControllerInterface $term_storage) {
   
$this->moduleHandler = $module_handler;
   
$this->entityManager = $entity_manager;
   
$this->termStorage = $term_storage;
  }
 
/**
   * {@inheritdoc}
   */
 
public static function create(ContainerInterface $container) {
   
$entity_manager = $container->get('plugin.manager.entity');
    return new static(
     
$container->get('module_handler'),
     
$entity_manager,
     
$entity_manager->getStorageController('taxonomy_term')
    );
  }
 
/**
   * Returns a rendered edit form to create a new term associated to the given vocabulary.
   *
   * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary
   *   The vocabulary this term will be added to.
   *
   * @return array
   *   The taxonomy term add form.
   */
 
public function addForm(VocabularyInterface $taxonomy_vocabulary) {
   
$term = $this->termStorage->create(array('vid' => $taxonomy_vocabulary->id()));
    if (
$this->moduleHandler->moduleExists('language')) {
     
$term->langcode = language_get_default_langcode('taxonomy_term', $taxonomy_vocabulary->id());
    }
    return
$this->entityManager->getForm($term);
  }
}
?>

About 86 lines for just a simple addForm method.

Introduce a ControllerBase class for routing controllers that only contain limited glue code. This base controller is container aware and expose a number of utility methods to the Container services. In this way, simple controllers, i.e., "thin" Controllers containing limited code, could extend this base class to avoid lots of boilerplate code.

Now, see 'TaxonomyController' again:

<?php
/**
* @file
* Contains \Drupal\taxonomy\Controller\TaxonomyController.
*/
namespace Drupal\taxonomy\Controller;
use
Drupal\Core\Controller\ControllerBase;
use
Drupal\taxonomy\VocabularyInterface;
use
Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides route responses for taxonomy.module.
*/
class TaxonomyController extends ControllerBase {
 
/**
   * Returns a rendered edit form to create a new term associated to the given vocabulary.
   *
   * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary
   *   The vocabulary this term will be added to.
   *
   * @return array
   *   The taxonomy term add form.
   */
 
public function addForm(VocabularyInterface $taxonomy_vocabulary) {
   
$term = $this->entityManager()->getStorageController('taxonomy_term')->create(array('vid' => $taxonomy_vocabulary->id()));
    if (
$this->moduleHandler()->moduleExists('language')) {
     
$term->langcode = language_get_default_langcode('taxonomy_term', $taxonomy_vocabulary->id());
    }
    return
$this->entityManager()->getForm($term);
  }
}
?>

Only 36 lines, much simplier.

For controller which may contain sufficiently complex logic and is worth testing, it should use ContainerInjectionInterface, instead of this base class.

A list of helper methods:

  • public function l($text, $route_name, array $parameters = array(), array $options = array())(), which allows to provide a link using route names and parameters.
  • public function redirect($route_name, array $route_parameters = array(), $status = 302);, which allows to redirect to a specified route.
  • public function url($route_name, array $route_parameters = array(), array $options = array());, which allows to create an url using specified route name/parameters.
Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Module developer documentation done
Examples project: 
Not done
Coder Review: 
Coder review done
Coder Upgrade: 
Not done
Other: 
Other updates done