entityTypeManager()
is a method defined from the ControllerBase
class, even in Drupal 10. ControllerBase::$entityTypeManager
is one of its properties, but I would use ControllerBase::entityTypeManager()
because it initializes that property, if it was not already initialized.
protected function entityTypeManager() {
if (!isset($this->entityTypeManager)) {
$this->entityTypeManager = $this->container()->get('entity_type.manager');
}
return $this->entityTypeManager;
}
If that is not one of the parent classes for the controller, I would do as the documentation for that class says (if the controller class does not contain trivial code) and use the ContainerInjectionInterface
to implement the create()
method necessary to inject the required dependencies.
For reference, this is the suggestion given in the ControllerBase
documentation. (Emphasis is mine.)
Controllers that use this base class have access to a number of utility methods and to the Container, which can greatly reduce boilerplate dependency handling code. However, it also makes the class considerably more difficult to unit test. Therefore this base class should only be used by controller classes that contain only trivial glue code. Controllers that contain sufficiently complex logic that it's worth testing should not use this base class but use ContainerInjectionInterface
instead, or even better be refactored to be trivial glue code.
If you want to have available a entityTypeManager()
method without extending that class, I would use code similar to the following one.
use Drupal\Core\Entity\EntityTypeManager;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Controller implements ContainerInjectionInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* Constructs a new Controller object.
*
* @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
* The entity type manager.
*/
public function __construct(EntityTypeManager $entityTypeManager) {
$this->entityTypeManager = $entityTypeManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('entity_type.manager');
}
/**
* Retrieves the entity type manager.
*
* @return \Drupal\Core\Entity\EntityTypeManager
* The entity type manager.
*/
public function entityTypeManager() {
return $this->entityTypeManager;
}
}
Otherwise, to simply use the ControllerBase
class, I would take the BookController
code as example.
use Drupal\book\BookExport;
use Drupal\book\BookManagerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Controller routines for book routes.
*/
class BookController extends ControllerBase {
/**
* Constructs a BookController object.
*
* @param \Drupal\book\BookManagerInterface $bookManager
* The book manager.
* @param \Drupal\book\BookExport $bookExport
* The book export service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
*/
public function __construct(BookManagerInterface $bookManager, BookExport $bookExport, RendererInterface $renderer) {
$this->bookManager = $bookManager;
$this->bookExport = $bookExport;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('book.manager'),
$container->get('book.export'),
$container->get('renderer'));
}
/**
* Prints a listing of all books.
*
* @return array
* A render array representing the listing of all books content.
*/
public function bookRender() {
$book_list = [];
foreach ($this->bookManager->getAllBooks() as $book) {
$book_list[] = Link::fromTextAndUrl($book['title'], $book['url']);
}
return [
'#theme' => 'item_list',
'#items' => $book_list,
'#cache' => [
'tags' => $this->entityTypeManager()->getDefinition('node')->getListCacheTags(),
],
];
}
}
BookController
adds its own dependencies, but it can still use $this->entityTypeManager()
to get the entity type manager.
As for the exception thrown in line 135, this is the code that causes that exception.
$entity_types = $this->getEntityTypes();
$parameter_definitions = $route->getOption('parameters') ?: [];
$result = FALSE;
if (is_array($controller)) {
[$instance, $method] = $controller;
$reflection = new \ReflectionMethod($instance, $method); // Line 135
}
else {
$reflection = new \ReflectionFunction($controller);
}
For some reason, PHP does not found the \Drupal\mymodule\Controller\MyController
class, for example because the class namespace is wrong. (There could be other reasons for which PHP autoload cannot load that class, but I could not recall them at the moment.)
ControllerBase
as parent class, or Drupal could not first complain thatDrupal\mymodule\Controller\MyModuleController::entityTypeManager()
is an undefined method (which means Drupal found theDrupal\mymodule\Controller\MyModuleController
class).