Reputation: 9552
Assume I have a User
and a Message
entity in my Symfony2 app, with a oneToMany
relation between both entities, so a User can have multiple messages, and I want to display the number of unread messages in my main navigation like this
where (6)
is the number of unread messages. In order to fetch this amount of unread messages per user Controller independently, I could think of defining a User
entity method:
public function getUnreadMessagesCount() {
$unreadMessagesCount = 0;
foreach($this->messages as $message) {
if($message->isUnread()) {
$unreadMessagesCount++;
}
}
}
and call it in my menu.html.twig
{% set umc = app.user.getUnreadMessagesCount() %}
{% if umc > 0 %}
({{ umc }})
{% endif %}
But for performance reasons, I would want to avoid looping through the entire set of messages just to check whether it is unread or not. So I would prefer to fetch it via a DQL call (and place this fetch in the UserRepository
class)
$query = $em->createQuery("
SELECT COUNT(m.id) AS umc
FROM AcmeBundle:User u
JOIN AcmeBundle:Message m
WITH u.id = m.user_id
WHERE m.unread = true
AND u.id = :uid");
But afaik it's bad practice to use repository methods or to use the entitiy manager (or Doctrine) in entity classes.
I thought about fetching the value in a service and inject this into my entity. But it also is not recommended to inject services into entites.
So what is a legit way to fetch this value and output it in all templates (may also be without entity methods, e.g. by injecting the value into all Controllers)?
Upvotes: 2
Views: 317
Reputation: 10513
I used another solution to get data from a repository.
First, define the service:
## in bundle/Resources/config/services.yml
services:
YOUR_BUNDLE.twig.NAME_OF_THE_EXTENSION:
class: YOUR\BUNDLE\Twig\CLASSNAME
arguments:
- @service_container
tags:
- { name: twig.extension }
Then define the Twig extension class:
# YOUR_BUNDLE/Twig/CLASSNAME.php
<?php
namespace YOUR\BUNDLE\Twig;
class CLASSNAME extends \Twig_Extension
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function getGlobals()
{
return(array(
'unreadMessagesCount' => $this->container->get('doctrine')
->getManager()
->getRepository('YOUR_BUNDLE:UserRepository')
->getUnreadMessagesCount()
));
}
public function getName()
{
return 'NAME_OF_THE_EXTENSION';
}
}
Upvotes: 2
Reputation: 9552
I don't really like this approach, but - for completeness - I found this:
You can set the service a twig global variable in
config.yml
, e.g
#app/config/config.yml
twig:
globals:
your_service: "@your_service"
See here.
So simply define your service
class AcmeService {
public function __construct() {
// construct
}
public function myMethod() {
// do stuff
}
}
declare this service in your config.yml
, define it as twig globale (see quoted answer above) and you can use your method in your twig file like this
{{ your_service.myMethod() }}
Upvotes: 2