Symfony2 - Twig - How can I send parameters to the parent template? - php

I am working on a PHP project using Symfony2 with Twig templating, and I can't find a solution for this problem.
I have an admin bundle and all the templates extend from admin base which has a master template with a menu.
I need to set the current tab of the menu in the base template of the page to selected when the user is on that page.
Is there any way to pass parameter to the base template through extends?

Here is a simple example:
base.html.twig:
{# base.html.twig #}
...
<ul>
<li{% if menu_selected|default('one') == 'one' %} class="selected"{% endif %}>One</li>
<li{% if menu_selected == 'two' %} class="selected"{% endif %}>Two</li>
<li{% if menu_selected == 'three' %} class="selected"{% endif %}>Three</li>
</ul>
...
page2.html.twig:
{# page2.html.twig #}
{% extends 'YourBundle::base.html.twig' %}
{% set menu_selected = 'two' %}
Output from rendering page2.html.twig:
<ul>
<li>One</li>
<li class="selected">Two</li>
<li>Three</li>
</ul>

A better way that I just discovered is the basic approach by checking the route for the shortcut route name:
<li class="{% if app.request.attributes.get('_route') == 'homepage' %}active{% endif %}">Home</li>
Or another way is to name all your route shortcut names according to the group it belongs to. For example all the routes from your products controller start with "product_...." and then in the template you can do this:
<li class="{% if app.request.attributes.get('_route') starts with 'product' %}active{% endif %}">

Related

Twig loop. control class names

Im trying in Twig to set different classes depending on how may items that gets rendered. Eg, if only one, if only two, if only three etc I want to set a different class on the item. How would I do that?
<ul>
{% for item in items %}
<li>
{% include 'components/list/person.twig' with item %}
</li>
{% endfor %}
</ul>
If you want to know in advice the length of the loop, you can use the predefined loop variable that is named length:
loop.length: The number of items in the sequence
as example:
{% for user in users %}
{{ loop.index }}/{{ loop.length }} - {{ user.username }}
{% endfor %}
hope this help
I am not sure that i understood your question or not...
But if you want to use different classes on base of index of loop then you can use loop.index in loop.
Hope this will help you
<ul>
{% for item in items %}
{℅ if loop.index == 1 ℅}
// Set class here
{℅ endif %}
<li>
{% include 'components/list/person.twig' with item %}
</li>
{% endfor %}
</ul>

Creating a dynamic tree in symfony 2

I am beginner in symfony 2. I have a project and I want to create a dynamic tree using css, this tree will display my categories levels.
I already tried to do it by myself, I was able to display the first 3 levels of my categories using 3 loops, but other levels are not displaying.
What I want is to know if I can use recursion or an other way to display all categories as a tree.
this the action method i used :
public function afficherArborescenceAction(){
$em = $this->getDoctrine()->getManager();
$categories = $em->getRepository('PortfolioBundle:Categorie')->findByCategorieParent();
$sousCategories = $em->getRepository('PortfolioBundle:Categorie')->findSousCategories();
return $this->render('AdministrateurBundle:NouvelleCategorie:showCategories.html.twig',array('categories'=>$categories,'sousCategories'=>$sousCategories));
}
This my html code :
<div style="border:1px #999999 solid;border-radius: 5px;width:350px;margin: 100px auto;padding:10px;">
<p>Les catégories:</p>
{% for categorie in categories %}
<ul class="tree">
<li>{{ categorie.libelle }}
{% for sousCategorie in sousCategories %}
<ul>
{% if sousCategorie.categorieParent == categorie.id %}
<li>
{{ sousCategorie.libelle }}
{% for sous in sousCategories %}
{% if sous.categorieParent == sousCategorie.id %}
<ul>
<li>
{{ sous.libelle }}
</li>
</ul>
{% endif %}
{% endfor %}
</li>
{% endif %}
</ul>
{% endfor %}
</li>
</ul>
{% endfor %}
This is the current tree i get, using the code above :
By using StofDoctrineExtensionBundle it is very simple to do what you want. For example this would generate nested <ul> of your category tree:
$htmlTree = $repository->childrenHierarchy(
null,
false,
[
'decorate' => true,
'nodeDecorator' => function ($node)
{
return "$node[name]";
},
//'rootOpen' => '<ul>', leave it as is
//'rootClose' => '</ul>',
'childOpen' => function ($node)
{
return "<li data-node-id=\"$node[id]\">";
},
'childClose' => '</li>',
],
true
);
$io->writeln($htmlTree);
Here is fully working example, complete process is covered, from configuring to the more advanced queries: Hierarchical Data in Relational Databases with Symfony 4 and Doctrine.
Check there, with the component Tree:
https://github.com/stof/StofDoctrineExtensionsBundle/blob/master/Resources/doc/index.rst
It can do what you need exactly

Symfony2: local changes for same twig view

I've implemented the Jmsi18nRountingBundle in my symfony2 application : symfony2: how to parameter localization so we can have 2 languages?
I thought it was it but now that I have started making some translations, I realize that the locale used to translate the text surrounded by the trans tag in twig varies in a single template.
See the ouput of the profiler :
Any idea of what might be causing this ?
In my template, I have the following code:
{# src/FoodMeUp/CoreBundle/Resources/views/Default/header.html.twig #}
{% trans_default_domain 'header' %}
<header>
<section id="toprow" class="greybg">
<ul class="wrapperext">
<li id="startup_button">
{% trans %}howto{% endtrans %} <span>{% trans %}start{% endtrans %} </span><i class="fa fa-question-circle"></i>
</li>
<li id="top_row_message" class="padding-h">{{ socialButtons({url: 'home', padding: false , facebookLike : { layout : 'button_count'}, facebookShare : { layout : 'button_count'}, twitter : { count : 'horizontal'} , googleplus : { annotation: 'bubble'} }) }}</li>
</ul>
</section>
<section id="header_content" class="padding-v whitebg clearfix">
<div id="pres" class="wrapper fmu_flex space-between center">
<h2 class="align_left">{% trans %}description.left.normal{% endtrans %} <strong>{% trans %}description.left.strong{% endtrans %}</strong>...</h2>
<a id="logo" href="{{ path('home') }}"><img src="{{ asset('images/foodmeup_horizontal_w280.png') }}" alt="logo Foodmeup" class="margin-auto block"></a>
<h2 class="align_right">...{% trans %}description.right.normal{% endtrans %} <strong>{% trans %}description.right.strong{% endtrans %}</strong> {% trans %}description.right.normal2{% endtrans %}</h2>
</div>
{% if isAuthenticated() == false %}
<div id="create_account_button" class="wrapper align_center">{% trans %}create.account{% endtrans %}</div>
{% endif %}
</section>
</header>
and I have two files for my translations, header.fr.xlf and header.en.xlf :
en :
howto: 'How to'
start: 'start'
connect: 'Connect'
description.left.normal: 'FoodMeUp is a platform of'
description.left.strong: 'services'
description.right.normal: 'dedicated to'
description.right.strong: 'professionals'
description.right.normal2: 'of the food industry'
create.account: 'Create your account in one minute'
fr:
start: 'démarrer'
howto: 'Comment'
connect: 'Connexion'
description.left.normal: 'FoodMeUp est une plateforme de'
description.left.strong: 'services'
description.right.normal: 'dédiée aux'
description.right.strong: 'professionnels'
description.right.normal2: 'des métiers de bouche'
create.account: 'Créez votre compte en 1 minute'
EDIT 1:
I have figured out this might be a priority issue of my locale listener.
If I set the priority to 17, then the locale stays the same for the template. This is because there is a translation listener of priority 10 which changes the locale with the request default value for the locale, which is actually set by the locale listener by reading the session value.
I still have different locales for a given template and the one generated with render(controller())... investigating this.
Found the solution, ouf, this is what follows my edit.
In addition to adding a priority of 17 to my locale listener,I neeeded to make sure it also handled subrequests.
See the corrected code here : symfony2: how to parameter localization so we can have 2 languages?

Symfony2 internal route in Twig render function

My layout.html.twig:
{{ render(controller('AcmeDemoBundle:Page:mainmenu')) }}
The Page controller retrieves all pages from the Doctrine and renders mainmenu.html.twig with a set of pages.
My mainmenu.html.twig:
{% if menu_pages is defined %}
{% for page in menu_pages %}
<li class="{% if app.request.attributes.get('_internal') == '_page_show' and app.request.get('id') == page.id %}active{% endif %}">{{ page.title|e }}</li>
{% endfor %}
{% endif %}
But no active class is displayed. As far as I understand the problem is in internal routing. How to fix that?
Better do not use {{ render(controller('AcmeDemoBundle:Page:mainmenu')) }}. It work more fast and comfortable when you use services instead. You can create a service which will show menu on any page where you include them. And in service you can easy get access to current _route for add active class.
But if you really need to use {{ render(controller('AcmeDemoBundle:Page:mainmenu')) }}, so you need pass to them a current request like:
{{ render(controller('AcmeDemoBundle:Page:mainmenu', {'request': app.request})) }}
and then in action pass request to twig:
public function mainmenuAction($request) {
return $this->render('AcmeDemoBundle:Page:mainmenu.html.twig', array('request' => $request));
}
and in twig use this request:
{% if menu_pages is defined %}
{% for page in menu_pages %}
<li class="{% if request.get('_route') == '_page_show' and request.get('id') == page.id %}active{% endif %}">{{ page.title|e }}</li>
{% endfor %}
{% endif %}

Twig Navigation done right (appending variables to render)

I was trying to get a navigation to work in symfony using twig. It didn't work as I expected. I want a service or another controller to provide the navigation.items, so I don't have to include it in every response object. So that if I'd render like this:
...
return $this->render('AcmeDemoBundle:Default:index.html.twig', array('title' => $slug));
}
I would be able to include this:
{# app/src/Acme/Bundle/AcmeDemoBundle/Resources/views/Navigation/navigation.html.twig #}
<nav>
<ul>
{% for item in navigation.items %}
<li>
{{ item.title }}
</li>
{% else %}
<li>The menu is empty.</li>
{% endfor %}
</ul>
</nav>
Try to implement KnpMenuBundle: https://github.com/KnpLabs/KnpMenuBundle
This bundle does everything you ask.
The docs describe a simple implementation: https://github.com/KnpLabs/KnpMenuBundle/blob/master/Resources/doc/index.md

Categories