2

I am trying to make a messaging system and I'm facing a small problem. I have a bigger template that displays my menu and my content. The menu includes the number of new messages, and the content can be any page(compose a new message, inbox, sent).

The problem is that I have to render each of the small templates by passing the number of new received messages to each of them, calling the doctrine each time and repeating code. Is there any way to send the number only to the parent template?

Here are my templates:

This is the parent containing the newmsg variable that gives me problems.

{% extends "::base.html.twig" %}

{% block body %}

    <a href="{{ path('private_message_inbox') }}">  inbox</a>  : {{ newmsg }}
    <a href="{{ path('private_message_sent') }}">sent</a>
    <a href="{{ path('private_message_new') }}">compose</a>

{% endblock body %}

Here is an example of child template:

{% block body %}
    {{ parent() }}

    {% if messageList %}
        {% for message in messageList %}
            <li><a href="{{ path('private_message_view',{'msg': message.id}) }}">title</a> = {{ message.title|e }}</li>
            <li>cont= {{ message.content|e }}</li>
            <li>data= {{ message.date|date('d-m-Y H:m:s') }}</li>
            <li>sender= {{ message.sender|e }}</li>
            <hr>
        {% endfor %}
    {% else %}
        <div>no messages</div>
    {% endif %}
{% endblock body %}

The problem is that each child template is asking me for the newmsg variable

$messages = $this->getDoctrine()->getRepository('MedAppCrudBundle:Message');
    $newMessagesNo = count($messages->findBy(array('seen' => '0', 'receiver' => $this->getUser())));
    return $this->render(
        'MedAppCrudBundle:UserBackend\Message:new.html.twig',
        array(
            'form' => $form->createView(),
            'newmsg' => $newMessagesNo,
        )
    );

And I have to write this in every single controller. Any way I can shorten this problem?

George Irimiciuc
  • 4,573
  • 8
  • 44
  • 88
  • You could use a [render](http://symfony.com/doc/current/quick_tour/the_view.html#embedding-other-controllers). I'm not entirely sure this is the best approach. Twig isn't my strong point. You could also use [global variables in twig](http://symfony.com/doc/current/cookbook/templating/global_variables.html). – Andrei Aug 27 '15 at 08:53

1 Answers1

1

You could implement a service that gives back the newmsg value and call it on your parent template. Then it would not be necessary to pass the variable.

You can add a service in your bundle's services.yml with something like:

 services:
     newmessages:
         class: Full\Class\Name\NewMessagesService
         arguments: ["@doctrine.orm.entity_manager"]

Then, implement the Full\Class\Name\NewMessagesService class. Keep in mind that this class will need a constructor that receives an EntityManager argument. Something like:

  <?php
  namespace Full\Class\Name;
  class NewMessagesService{
     private $entityManager;

     public function __construct($entityManager){
         $this->entityManager = $entityManager;
     }

     public function methodToCalculate(){
          //Perform calculation and return result
     }
 }

Then, in your parent template, replace {{newmsg} with:

 {{ newmessages.methodToCalculate() }}
Oscar Pérez
  • 4,377
  • 1
  • 17
  • 36
  • Can I call EntityManager in a constructor? I remember I tried to call it in my class's constructor to define newmsg as one of it's class variables and I wasn't allowed. But this was a controller. – George Irimiciuc Aug 27 '15 at 08:56
  • No, you will not call it in the constructor. See code's new version, – Oscar Pérez Aug 27 '15 at 09:00
  • I've also looked into using a render from Andrew's reply from above, and it seems to do a similar job. Is it worth implementing a service, then? – George Irimiciuc Aug 27 '15 at 09:01
  • It depends. I think a service is cleaner and more in line with Symfony's philosofy... – Oscar Pérez Aug 27 '15 at 09:02
  • A bit of a problem, I did exactly like here but it tells me that newmessages doesn't exist in the template. I've declared the service in both the bundle and the app's yml file, but without success. Do I have to do something with the service in the controller? – George Irimiciuc Aug 27 '15 at 13:07
  • No, you don't. Could you please try to call it from the controller? Would it work? – Oscar Pérez Aug 28 '15 at 04:21
  • In the controller it does work, but I can't call it in the parent controller because that one is never called through a request. Only child controllers make a call. Unless I call the service in every child controller, but it still seems awkward rather than calling it only once in the parent template. I opened a related question http://stackoverflow.com/questions/32250927/call-services-in-templates?lq=1 – George Irimiciuc Aug 28 '15 at 05:12
  • @GeorgeIrimiciuc, look at http://stackoverflow.com/questions/13243638/symfony2-how-to-access-service-from-template – Oscar Pérez Aug 28 '15 at 06:58