Symfony 2 - missing mandatory parameters exception on twig extends - symfony

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.

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.

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

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)

Symfony2 - passing values between ESI and main request

I need to pass a value from the main controller in a route to the controller used by an ESI.
So a controller renders a Twig template and in Twig this is called:
{{ render_esi(url('route_name')) }}
The above renders a controller. It's those two controllers I need to pass information between.
I've noticed that using $request->attributes does't work, even though it would if one wasn't an ESI:
//these WON'T pass between master request and ESI
$request->attributes->set('the_value');
$request->attributes->get('the_value');
Sessions aren't ideal as I would need to ensure they were cleared on some occasions.
I really just want the same request to pass some information once. I was hoping that the $request->attributes would be shared as to me it's one request (although I believe Symfony calls it one master request with various sub-requests and I'm guessing $request->attributes are locked to that scope).
Passing it as a query param in the ESI call isn't good either as it can sometimes be an array of info that needs to be passed.
Any ideas?
You can pass arguments to your action like this:
{{ render_esi(controller('YourBundle:Default:news', { 'max': 5 })) }}
or use route parameters like this
{{ render_esi(url('latest_news', { 'max': 5 })) }}
as correctly answered in this question.

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