For loop with two database queries in Twig - php

I'd really love if anyone can help, I'm trying to figure out a way to loop through two queries in Twig. I can create it in PHP but I'm having doing the same thing on Twig. This is how I'd normally do it on PHP:
foreach($items as $item){
$product_id = $item;
$products = $app->db->table('products')->where('id', $product_id)->first();
echo "<li>" . $products->title . "</li>";
}
The above code will work fine but on Twig it will not loop to the next loop, but it will keep on looping the same thing.
Kindly help if you know how I can use Twig for loop like I use it above. I'm querying it using Laravel Eloquent in Slim.
This is what I did:
The controller
$products = $app->db->table('products')->where('trash', '0')->first();
The View
{% for item in items %}
{% set product_id = item.id %}
<li> {{ products.title }}</li>
{% endfor %}
It will only show the first row and repeat the samething.

Don't attempt to run queries from a template. Do it in the controller and pass the result to the template.
Also $items appears to be an array of IDs, so you should be able to load all of the products at once with a where-in condition (instead of multiple queries):
Controller:
$products = $app->db->table('products')->whereIn('id', $items)->get();
// pass $products to the template as "products"
Twig template:
{% for product in products %}
<li>{{ product.title }}</li>
{% endfor %}

Related

Loop through categories, childcategories and products in twig

My table structure in my database is like this:
Some categories have a child category and some not. A product can belong to:
Child category
Parent Category (this category has NO child categories)
My array looks like this:
Category A is a parent category. Category B - Head is also a parent category. Category B - Child is a child category of B - Head.
Now I would like to show this array like this:
But I'm stuck on how to know if it's a category or a list of products. Can someone help me with this?
If you're using Doctrine Models (which if you're using Symfony, you should be) then all you're doing is looping through the methods on the object.
Quick and dirty example with few assumptions e.g. using #Template() annotation and standard DAOs aka EntityManager[s] as well as having getChildren() and getProducts() methods on the Category.php (AKA model/entity)
On the controller
/**
* #Route("/products", name="all_products")
* #Template()
*/
public function someAction()
{
...
$categories = $this->getCategoryManager()->findBy([]);
...
return [
'categories' => $categories
];
}
In your twig template
{% if categories|length > 0 %}
{% for category in categories %}
{% if category.children|length > 0 %}
... Here you create the HTML for nested ...
{% else %}
... Here you create the HTML for Category ...
{% for product in category.products %}
... Here you create the HTML for products ...
{% endfor %}
{% endif %}
{% endfor %}
{% else %}
.... some html to handle empty categories ....
{% endif %}
If the HTML for nested is repeated in the HTML for flat (very likely scenario) then you can create and include a macro to spit that out for you.
This is basic, but I think it pretty much covers what you're asking if I'm understanding your question properly.
Btw, you should definitely read the docs for twig and Symfony since they have examples like these everywhere.
I'll edit this answer if you respond as appropriate. Right now you haven't posted enough information to really guide you properly but hope this helps.
You could use a recursive macro. In the macro you either print the list of products or print the list of categories and then call itself.. and so on...
{% macro navigation(categories, products) %}
{% from '_macros.html.twig' import navigation %}
{% if categories|length > 0 or products|length > 0 %}
<ul>
{% for category in categories %}
<li>
{{ category.name }}
({{ category.children|length }} child(ren) & {{ category.products|length }} products)
{{ navigation(category.children, category.products) }}
</li>
{% endfor %}
{% for product in products %}
<li>{{ product.name }}</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
You would just use this in a template like...
{% from '_macros.html.twig' import navigation %}
{{ navigation(array_of_categories) }}
This just creates a basic set of nested unordered lists but then can be used with any HTML you want, obviously.
For a fiddle see http://twigfiddle.com/mzsq8z).
The fiddle renders as the following (twigfiddle only shows the HTLM rather than something you can use to visualize)...

Limit, pagination in Symfony

I am trying to add pagination to my current project. I am pretty new to Symfony so I am not sure if there is something out there that can help me build such. My current code looks like this:
Controller class:
class MovieDisplayController extends Controller
{
public function showAction()
{
$movies = $this->getDoctrine()->getEntityManager()->getRepository('AppBundle:Movie')->FindAll();
return $this->render('movies/index.html.twig', array(
'movies' => $movies
));
}
}
Twig template:
{% block body %}
{% if movies|length == 0 %}
There are no movie items available. Add a movie here to get started.
{% elseif movies|length != 0 %}
These are the results: <br />
<ul>
{% for x in movies %}
<li>Title: {{ x.title }} - Price: {{ x.price }} - Edit - Details - Delete</li>
{% endfor %}
</ul>
Add more movie entries
{% endif %}
{% endblock %}
This will return all results within the database. I would like to only show 5 results (rows per page) and add paging buttons below the list and I wonder how/if this is possible?
The findAll() function will not work if you want to set limit.
You can try KnpPaginatorBundle to add pagination in symfony. It will work with fine to add pagination.
https://github.com/KnpLabs/KnpPaginatorBundle

Name of Twig variable in a Twig variable

I get a list of collections right from Doctrine and I store them into an array.
For example:
$data['collList'] = $heyDoctrine->giveMeMyColls();
But I also want to retrieve some informations about these collections.
I store it into $data['collectionId'].
Until this point, everything works fine.
But in my Twig template, I want to create ordered lists with the name of my collection and every item of this list would be an information about this collection.
So, in PHP, I would do this:
foreach($data['collList'] as $collItem){
echo $collItem['name'];
echo '<ul>';
foreach($data[$collItem['id']] as $collItemData){
echo '<li>'.$collItemData.'</li>';
}
}
My problem is: how to do this with Twig?
I don't know how to say to Twig «hey, use «coll.id» as THE NAME of an other variable!
I've looked a bit and I've found the «attribute» function, but I wasn't able to make it work.
How should I do that?
Thanks a lot.
So, try next twig code:
{% for key, collItem in data.collList %}
{{ collItem.name }}
<ul>
{% for collItemData in data[collItem.key] if key == 'id' %}
<li> {{ collItemData }} </li>
{% endfor %}
</ul>
{% endfor %}

Symfony2 Twig Get Total Count for Child Entity

The following entities exist, Farm, Barn and Animals. A Farm can have many Barns and a Barn many Animals.
When displaying a Farm in a TWIG template the number of Animals should be shown as well.
What is the best way to do this?
I have create a TWIG extension which allows me to easily show the number of barns.
public function totalFieldFilter($data, $getField='getTotal') {
$total = count($data->$getField());
return $total;
}
In my template I would use {{ farm|totalField('getBarns') }}, I could easily extend this to write another custom function like so:
public function totalFieldFilter($farm) {
$total = 0;
foreach($farm->getBarns() AS $barn) {
$total += count($barn->getAniamls());
}
return $total;
}
Although this would work, is there a better way and can it be made more generic? What if I wanted to count Legs on Animals? Or how many Doors a Barn has, I would have to write a custom TWIG extension each time.
Use Entity accessors :
{% for farm in farms %}
{{ farm.name }}
{% set barns = farm.getBarns() %}
Barns count = {{ barns|length }}
{% for barn in barns %}
{% set animals = barn.getAnimals() %}
{{ barn.name }} animals count : {{ animals|length }}
{% endfor %}
{% endfor %}
You are looking for the length filter
When used with an array, length will give you the number of items. So, if your array is farm.barns, you can just use {{ farm.barns|length }}

Twig - Using multiple child templates within parent

I have the following two templates
parent.html
<ul class="basketItems">
{% for item in items %}
{{ item | raw }}
{% endfor %}
</ul>
child.html
<li>
{{ link.title}}
</li>
Now i would like to have multiple instances of child.html within parent.html. In My php code I have to loop through the children and pass in the link object so that the link.title variable can be populated.
My current code involves me loading in parent.html, then rendering each child and creating a php array, then rendering the parent.html and passing in all the generated html of the children as array entries (see below). Is there any easy way to do this without having to build up a php array of html snippets by possibly using Twig blocks.
$parent = $twig->loadTemplate("parent.html");
foreach ($items as $item) {
$child = $twig->loadTemplate("child.html");
var $link = link::get($item->id));
/* do some other database retreival / data processing work */
$childHtml[] = $child->render(array('item' => $link));
}
$parent->render(array('items' => $childHtml));
Thanks in advance
try this:
{% for item in items %}
{% include "child.html" %}
{% endfor %}
Here in Manual: http://twig.sensiolabs.org/doc/templates.html
And for PHP Part:
$parent = $twig->loadTemplate("parent.html");
for ($i =0; $i < count($items); $i++) {
/* do some other database retreival / data processing work */
/* add additional information to array */
$items[i]['link'] = link::get($item->id));
}
$parent->render(array('items' => $childHtml));
Do the controller stuff and pass that clean array to template engine. Don't mix that.
It is always better to follow "Separation of concerns" principle:
http://en.wikipedia.org/wiki/Separation_of_concerns

Categories