Question

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

  • Home
  • Whatever
  • Messages (6)
  • My Profile

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)?

Was it helpful?

Solution

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';
    }
}

OTHER TIPS

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() }}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top