1

Following my last question I can't manage to call the service from the template. I did exactly like in the answer, but I get 'Variable "newmessages" does not exist' in the template.

I also tried returning the service in the parent template, but the parent is never called since there is no request to it, the requests are done only to child templates.

public function indexAction(){
    $locationService = $this->container->get('newmessages');


    return $this->render(
        'MedAppCrudBundle:UserBackend\Message:index.html.twig',
        array('newmessages'=>$locationService->methodToCalculate())

    );
}

How to call service from parent template? The answer from last question doesn't work.

Community
  • 1
  • 1
George Irimiciuc
  • 4,573
  • 8
  • 44
  • 88

2 Answers2

1

The answer to your question is quite simple. You expose the service as a twig global variable. Based on your example, you should add something similar to your config.yml

twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    globals:
        newmessages: "@newmessages"

To use it in your twig, you would just write {{ newmessages.methodToCalculate() }}.

You can read more about this in the How to Inject Variables into all Templates documentation page.

Here is a more detailed example:

// Add this to config.yml
twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    globals:
        newmessages: "@newmessages"

// Add this to services.yml (or if you're using older version of Symfony, add it to config.yml as well)
services:
    newmessages:
        class: App\YourBundle\Service\NewMessages

// The NewMessages service class
<?php

namespace App\YourBundle\Service;

class NewMessages {

    public function methodToCalculate() {
        return "location calculated.";
    }

}

?>

 // in your twig template do this
 {{ newmessages.methodToCalculate() }}  // outputs "location calculated."
tftd
  • 16,203
  • 11
  • 62
  • 106
  • Hm, is there no problem if it is globally declared? I want to use it only in a few templates and being able to use it in all of them seems bad to me. – George Irimiciuc Aug 27 '15 at 13:58
  • If you're not using [Lazy service injection](http://symfony.com/doc/current/components/dependency_injection/lazy_services.html) your service is already loaded either way so it's pretty much the same thing. if you use `Lazy Services` then it would only be instantiated when you actually call a method from your service. – tftd Aug 27 '15 at 14:01
  • I'm getting 'Attempted to load class "NewMessagesService" from namespace "MedApp\CrudBundle\MedAppCrudBundle\Services". Did you forget a "use" statement for another namespace?' – George Irimiciuc Aug 27 '15 at 14:04
  • You're probably doing something wrong. I've updated my answer with an oversimplified example of how it should be. – tftd Aug 27 '15 at 14:13
1

You can expose your service as a twig function and use it in the twig statement. See the full doc here. As example, define an extension as:

services.yml

#########  TWIG EXTENSION
    acme.message_helper_twig_extension:
        class: Acme\MessageBundle\Twig\MessageHelperExtension
        arguments: [@newmessages]
        tags:
            - { name: twig.extension }

And implement it as follow:

namespace Acme\MessageBundle\Twig\MessageHelperExtension;



class MessageHelperExtension extends \Twig_Extension {


    protected $newMessages;


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



    public function getFunctions()
    {
        return array(
            //////////////////////////////////
            'twig_method_reference_name'=> new \Twig_Function_Method($this, 'getMessages'),
        );
    }

    public function getMessages()
    {
        return $this->newMessages->getMessages()
    }
    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    public function getName()
    {
        return 'message_helper';
    }

} 

Then you can use it in the twig as:

{{ twig_method_reference_name() }}

Hope this help

Matteo
  • 37,680
  • 11
  • 100
  • 115
  • So everytime I have a parent twig with a variable I have to define a service and then define it as twig extension? Sounds like a lot of pointless work and it seems like simply calling it in every controller would be a better solution. Or am I wrong? – George Irimiciuc Aug 27 '15 at 14:07
  • a twig extension is only a manner for expose a service to the twig layer. The `newmessages` is suppose is a service that return, in the method exposed, the number of new messages to the twig. Hope this clarify my intent – Matteo Aug 27 '15 at 14:10
  • Although this is a technically valid answer, I believe it adds a bit more complexity to the equation - one more service, one more class (which is a wrapper around the original). IMHO, twig extensions are mainly used to further extend core twig functionality like additional functions and filters. – tftd Aug 27 '15 at 14:29