Twig Navigation done right (appending variables to render) - php

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

Related

how do i select all tags in my twig template in grav?

I have the following code in my default.html.twig file to display all the titles of the blog pages with the tag : dog:
<ul>
{% for post in taxonomy.findTaxonomy({'tag':'dog'}) %}
<li>{{ post.title }}<span>(0)</span></li>
{% endfor %}
</ul>
What i would really like to do is find all the tags and not just the dog tag, so i did the following:
<ul>
{% for post in taxonomy.findTaxonomy({'tag':'all'}) %}
<li>{{ post.title }}<span>(0)</span></li>
{% endfor %}
</ul>
I changed the dog to all , but this does't really give me any results. I checked the documentation here for findTaxonomy , but it does't help much , also in the <span></span> inside the <li> , I would like to show how many articles for this perticular tag have been posted , eg. if there are five articles for the tag popcorn the html spitedd out should be:
<li>popcorn <span>(5)</span></li>. How do i achieve this ?
What about not using findTaxonomy and just iterate on all elements like this:
{% for post in yourCollection %}
<li>{{ post.title }}<span>(0)</span></li>
{% endfor %}
Eventually using an "if" statement on post.tag in case you want to check something (defined value, not '', etc).

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 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 %}

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

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 %}">

Categories