Can I make a user specific method accessible in all twig templates? - symfony

I am using Symfony2 with the FOSUserBundle. I have created a method where I ask if the user has done a specific action, e.g. $user->hasVoted().
In my twig templates, I want to be able to ask
{% if user.hasVoted() %}
in every template (because it has an implication on which other partials to include), but I don't want to pass the whole $user object to each template.
Is there any way to make this user method accessible in all templates (or I could also pass the boolean value to all templates) without having to pass this explicitly to each template?
I know about injecting variables into all templates from the Symfony cookbook.
# app/config/config.yml
twig:
# ...
globals:
ga_tracking: UA-xxxxx-x
But the cookbook entry either tells how to inject static values (as in this example above), or how to inject services.
Is there an easy way how to include this one boolean value without having to define a service and inject it like this:
# app/config/config.yml
twig:
# ...
globals:
user_has_voted: "#acme_user.user_has_voted"

The authenticated user is available via app.user everywhere.
{% if app.user.hasVoted() %}
Or the cleaner way, you create a twig extension like is_granted. This enables you, to change the logic behind in future, without changing the templates.

Yes you can, in your bundle boot() method:
// src/Acme/DemoBundle/AcmeDemoBundle.php
public function boot()
{
$hasVoted = $this->container->get('security.context')->getToken()->getUser()->hasVoted();
$this->container->get('twig')->addGlobal('user_has_voted', $hasVoted);
}

Maybe you want to use the "attribute" twig function?
Something like that i guess :
{% if attribute(user, hasVoted) %}
Hope this helps!
(as the doc specifies it here)

Related

Include a controller to get parameter in Twig

I would like to include a controller into my defaut layout (in app/) to get access to the parameters returned in the array. I don't want to render. I tried to use {{ render_hinclude(controller('L3O1ProjetBundle:Advert:index')) }}
But I'm not sure I understand what it does...
Thanks for your help!
Here is an example from the documentation.
{# app/Resources/views/base.html.twig #}
{# ... #}
<div id="sidebar">
{{ render(controller(
'AcmeArticleBundle:Article:recentArticles',
{ 'max': 3 }
)) }}
</div>
That calls AcmeArticleBundle:Article:recentArticles so first the bundle then the controller and then the function and render the output from that function.
http://symfony.com/doc/current/book/templating.html
It is little bit strange approach to get parameters from the controller without render. But if you really need to get some set of data inside Twig, then the best way will be create a twig extension that will return an array. And if you need same data be returned as the controller makes, better to rebuild the app's architecture: dedicate the controller logic to a service that will return needed values both controller/extension, inject the service to the controller and twig extension and returns data from the service.

Symfony 2: Deserialize object in twig

I'm a newbie and this is my first question so please be nice with me :)
In my Symfony 2 project I want to pass an $user object from my controller to the twig template. This object contains all relevant Information (like username, activepage ...) for rendering the view. My problem is that I would also like to put the result of mysqli database query inside the object. To be able to retrieve it in my twig template, I need two serialize the result object(array?) in the controller before passing. Unfortunately I dont know a way how to deserialize that object in twig( no twig filter available).
My questions:
Is this actually an elegant way or should i rather pass all objects in an array to the template?
Would it work to write a deserialize function inside the user class, which i can call in the twig template?
Will performance be ok?
How do the experienced people do this?
Thx for helping!
Built an array with your data in your controller and render it like this to your template :
return $this->render('yourbundle:example:index.html.twig', array(
'myArray' => $array,
Then in your template you have access to myArray like this :
{% for data in myArray %}
...
{% endfor %}
I made a service such a parameter bag which I can add parameters/values along the process, and render every parameters with twig so I can use them in javascript.
For that I had to use mostly JsonSerializable php interface (PHP 5.4+), and json_decode twig filter.
I think it is a nice way to pass variables to js like this because you can use this service when building your project.

Loading multiple files with Twig to access their variables

In Symfony 2, I want to load 2 arbitrary files from the Base.html.twig
Base.html.twig
A.html.twig
B.html.twig
All the UI is written in Base and I must get some variables out of A and B.
With Twig, how can I load the two files so I can access their variables in Base.html.twig.
It would also be interesting to know how to {% set %} a variable as a property bag (A and B would add stuff to it)
The ->render call loaded Base.html.twig
To my knowledge you'll have to pass it through from the controller.
Otherwise if i misread this, if the A and B files need variables you don't already have, you're best bet would be to embed a controller.
http://symfony.com/doc/current/book/templating.html#embedding-controllers

Symfony 2 - missing mandatory parameters exception on twig extends

I'm currently getting a very wired twig exception:
If I use the twig {% extends 'some:template' %}, I get the following twig exception:
An exception has been thrown during the rendering of a template ("The "_projectView" route has some missing mandatory parameters ("id").") in "xy:Project:view.html.twig".
But if I remove {% extends 'some:template' %}, the template is displayed correctly - this for my part rules out any problems with routing or the controller, it has to be a problem with the template but I can't figure it out. No variables are used in the parent templates.
Inside the template you're trying to extend you're trying to generate a url from a route '_projectView' but you don't provide all necessary parameters.
Either add a default id to your route ...
route_name:
pattern: /whatever/{id}
defaults: { id: 1 }
... or do something like this in your template:
{{ path('route', { 'id' : entity.id|default('1') }) }}
Quite simply, to display correctly, each twig needs to have all the variables it needs defined. They are either in the URL or passed into the render function. If any of these variables are missing, then Symfony will throw this error.
Given what you've said it seems to me that the twig you are extending has a variable in it that it wants. In all other places you have extended this twig, you have provided this variable already either in the URL or in one of the parent twigs and so it has not complained. In this case you try to use it and that variable is missing. So it complains.
Check to make sure your route passes in the right variable or that your controller passes the right variable into the render function.

Is a global variable for a Twig template available inside a Symfony2 controller?

A global variable for a Twig template can be defined inside the config.yml of a Symfony2 application as in the following:
twig:
globals:
var_name: var_value
Hence, in each Twig template the variable can be used as follows:
{{var_name}}
that will display
var_value
Do you know such a way to get the value of a global variable just inside a Symfony2 controller?
There doesn't seem to be a way to grab a particular value. But you can get the full array of globals from the twig service and then grab it's offset.
$twig = $this->container->get('twig');
$globals = $twig->getGlobals();
echo $globals['var_name'];
The right practice is to follow the official tutorial about Twig global variables in the Symfony's Cookbook. In practice, one should define a global variable that can be used in the controllers, e.g.:
; app/config/parameters.ini
[parameters]
my_global_var: HiAll
Then the variable is defined as global for the Twig templates
# app/config/config.yml
twig:
globals:
my_var: %my_global_var%
Hence, {{my_var}} will return HiAll but one should take care of the value once in the parameters.ini file.
So, the answer to the question is no! Or precisely, not in an effective way. MDrollette drawn a possible way!
I wasn't clear if you wanted to access the twig var in the controller, or just access a global var from the config. Here is how to access a global var from the config file...
You can place the value in the parameters section of the config..
parameters:
var_name: some_value
Now you can access it from the controller...
$value = $this->container->getParameter('var_name');
I think you'd better to use bundle configuration or DIC parameters for your value, and then add it to the twig globals (via your bundle extension class, for example), and not trying to do the opposite.

Resources