Creating a dynamic tree in symfony 2 - php

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

Related

Notification dropdown symfony

I have a notification icon. When user clicks on it, a dropdown appears and shows a list. I want to filter list to only show what's related to the connected user.
{% if app.user.roles[0] == "ROLE_DEVELOPPER"%}
<!-- dropdown notification message -->
<li class="dropdown">
<a title="Notifications" href="#fakelink" class="dropdown-toggle" data-toggle="dropdown">
<strong> <i class="fa fa-bell"></i></strong>
</a>
{% if notif_conges|length > 0 %}
<ul class="dropdown-menu animated half flipInX">
//this section
{% for notif_c in notif_conges %}
{% if notif_c.etat == "Acceptée" %}
<li><a>Votre demande : "{{notif_c.motif}}" Envoyée le "{{notif_c.CreatedAt|date('Y-m-d H:i:s')}}" a était traitée </a></li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
You want to filter notifications. Only notifications concerning connected users have to be displayed. You have two solutions:
The (very) bad way: Add a test in view
<ul class="dropdown-menu animated half flipInX">
//this section
{% for notif_c in notif_conges %}
{% if notif_c.etat == "Acceptée" and notif_c.user = app.user %}
<li><a>Votre demande : "{{notif_c.motif}}" Envoyée le "{{notif_c.CreatedAt|date('Y-m-d H:i:s')}}" a était traitée </a></li>
{% endif %}
{% endfor %}
</ul>
This is a bad way because you will forward all notifications to the view
The bad way: Add a filter in your controller
class YourController
{
public yourAction()
{
/** ... your code to handle notifications **/
foreach ($notifications as $notification) {
if ($notification->getUser()->getId() == $this->getUser()->getId)) {
$filteredNotification[] = $notification;
}
}
return $this->render('your_template_file', [
'notif_c' => $filteredNotifications
]);
}
}
This is still a bad way because you are retrieving all notifications from database.
The good way: Ask only the necessaries notification to your repository
Assuming, your notifications are retrieving with Doctrine, repository can filter data to only retrieve pertinent data.
class YourController
{
public yourAction()
{
/** ... your code is certainly something lke this: **/
$notificationRepository = $this->entityManager->getRepository('AppBundle:Notification');
$notifications = $notificationRepository->findAll();
render
return $this->render('your_template_file', [
'notif_c' => $notifications
]);
}
}
Replace findAll() by findBy(array $criteria) and add a criteria as first parameter:
class YourController
{
public yourAction()
{
$notificationRepository = $this->entityManager->getRepository('AppBundle:Notification');
$notifications = $notificationRepository->findBy([
'etat' => 'Acceptée',
'user' => $this->getUser(), //this could be a little different, I do not remember how to handle user in Sf2.8
]);
render
return $this->render('your_template_file', [
'notif_c' => $notifications
]);
}
}
Yo must use is_granted twig filter.
You can specify the user role that you one but IS_AUTHENTICATED_REMEMBERED role is given to all users who are logged in.
{% is_granted('IS_AUTHENTICATED_REMEMBERED') %}
<!-- dropdown notification message -->
...
{% endif %}

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 for loop stopping after two results (0, 1)

I have a loop that is getting passed the following array via a slim view in PHP:
'breadcrumbs' => array(
'path' => $breadcrumbs,
'directory' => $breadcrumbDirectory
)
Both $breadcrumbs and $breadcrumbDirectory are arrays.
I am using the following loop to display the contents via Twig.
<li>Home</li>
{% for breadcrumb in breadcrumbs %}
<li>{{ breadcrumbs.path[loop.index0] }}</li>
{% endfor %}
</li>
This code is working except it only displays the first 2 (0, 1) results. I am able to access indexes greater than 1 by calling {{ breadcrumbs.path[2] }} outside of the loop. Any help would be great, Thanks!
Your for loop is incorrect, you need to loop one of the two arrays inside of it :
<li>Home</li>
{% for path in breadcrumbs['path'] %}
<li>{{ path }}</li>
{% endfor %}
</li>

How to auto check checkboxes using Twig template?

I want to auto-check check boxes in the HTML. I've managed to get this to work, but it's kinda messy in the template:
<ul>
{% for tag in tags %}
{% set selected = false %}
{% for article_tag in article.tags %}
{% if article_tag.id == tag.id %}
{% set selected = true %}
{% endif %}
{% endfor %}
<li><input type="checkbox" name="tags[]" value="{{ tag.id }}" {% if selected %}checked{% endif %}> {{ tag.name }}</li>
{% endfor %}
</ul>
So the data I'm loading in is like this (in JSON format):
[
'tags' => [
{'id'=> 1, 'name'=>'Travel'},
{'id'=> 2, 'name'=>'Cooking'},
],
'article' => {
'tags' => [
{'id'=> 1, 'name'=>'Travel'},
],
}
]
Also, I'm not using Symfony (I'm using Slim's Twig library) so not sure if Symfony has some stuff in it's framework for doing stuff with Twig. If so, it won't work for me :(
The problem is the article is an array, so or you need to cycle on it for every tags array that contain or you simply access on it of the first element as follow:
{% for article_tag in article[0].tags %}
Instead of:
{% for article_tag in article.tags %}
See the result on this working twigfiddle
Hope this help

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