Keep entity object after getTitle() method in render() method in a custom controller
-
01-03-2021 - |
Question
I've setup my controller like this:
my_controller:
path: '/controller/{id}'
defaults:
_controller: '\Drupal\Mymodule\Controller\MyController::Render'
_title_callback: '\Drupal\Mymodule\Controller\MyController::getTitle'
requirements:
permission: 'access content'
Now, in my MyController.php I need to load an entity object (for which {id} is the id). Unfortunately, it seems I need to load my object twice. First, in my getTitle function because this is called first. Then again in my Render() function, which is called afterwards.
When I try to save the entity to my class as $this->entity It gets lost when the Render() function gets called. I tried to load via a constructor or create function, but these do not have access to the {id} slug in a proper manner.
What's the good practice way to make sure I need to load my entity object once for both functions?
Solution
When I try to save the entity to my class as $this->entity It gets lost when the Render() function gets called.
Use a service. Services are singletons and when the class resolver finds an existing service it loads the instance from the container and doesn't create a new class instance:
defaults:
_controller: 'my_service:render'
_title_callback: 'my_service:getTitle'
For good practice this is not really necessary in this case because entities are cached in memory automatically and loading an entity twice doesn't have a performance impact.
Good practice, though, would be to load the entity via route parameter upcasting:
foobar.view:
path: '/foobar/{foobar_placeholder}'
defaults:
_controller: '\Drupal\foobar\Controller\Foobar::content'
_title: 'Oh yeah foobar'
options:
parameters:
foobar_placeholder:
type: entity:foobar
Example from https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/parameter-upcasting-in-routes