Twig - Using multiple child templates within parent - php

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

Related

For loop with two database queries in Twig

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

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

Incremental for-loop in twig

I'm trying to add values in an array using twig. Does twig have an incremental for-loop feature? I'm aware of the standard for-loop in twig (e.g. {% for k in v %}), but I'm interested in a loop where I may specify things as detailed below in pure PHP:
<?php
//adding values in an array
$quantities = array('23', '23', '4', '45', '45');
$sum = 0;
for ($i = 0; $i < count($quantities); $i++) {
$sum += $quantities[$i];
}
echo "Sum: " . $sum . "\n";
?>
This is pretty much exactly what I'm looking to do with twig.
Thanks for any help, All.
You can check the Loop options in Twig
{% for quantity in quantities %}
// Do your stuff here with each individual quantity
// If you want to access the index ($i in your php sample)
{{ quantities[loop.index0] }}
{% endfor %}
Just take it as a reference and check the link provided to adapt it to your configuration.
Your approach could be improved even in php "natively"
Do you know about array_sum?
And of course, in twig you can create a twig_extension that in tandem with twig_filter could help you obtain what you want in a smart way.
To create a twig_extension with custom filter (remember to follow link that I have provided for "twig estension"):
public function getFilters()
{
return array(
new \Twig_SimpleFilter('sum', 'array_sum'),
);
}
Then you can use sum keyword into your twig template, as a filter of course
{% set sum = quantities|array_sum %}
If you really want the twig representation of your PHP code, this will be:
{% set sum = 0 %}
{% for value in quantities %}
{% set sum = sum + value %}
{% endfor %}
Sum: {{ sum }}
Anyway, #DonCallisto's approach is better.

twig: create custom tag that calls a functions

SETUP:
Twig 1.13.1
PHP 5.4.3
PROBLEM:
I am needing help setting up a custom tag that calls a function that i have already built...
Current Code:
Template Code
{% set stories = get_latest_stories(2, sports) %}
{% for story in stories %}
{{ story.headline }} <br>
{% endfor %}
Controller
$function = new Twig_SimpleFunction('getViewStories', function (section, limit) {
return news_stories::getStories(section,limit);
});
$twig->addFunction($function);
$twig->render("storyList.html");
GOAL:
No with that said I would like to use a custom tag like
{% get_latest_stories 2 sports %}
to call the same function as above. The new way looks nicer and is easier to follow
Why not fetch your stories in the controller instead of the template? This does not seem like a job for the view layer...
So, something like this:
$twig->render("storyList.html", array(
'stories' => news_stories::getStories($section, $limit)
));
Then, you'll have a stories variable available in your template.
here is simple example how to write twig extension
Following code is taken from my unfinished project
function file_import($value){
//some code here
return $value;
}
$app['twig']->addFunction('file_import', new Twig_Function_Function('file_import'));
usage
{{ file_import('value') }}

Creating breadcrumbs in symfony 2.1 using knpmenu bundle

What's the best way to create breadcrumbs using knpmenu bundle in symfony 2.1.x ? Aside from using 3-rd party bundles.
UPDATE:
Hi, theunraveler, sorry for late answer. Now I've been following your example and I'm stuck at one moment. Here, code below throws an exception, that
Missing argument 2 for Acme\DemoBundle\Menu\MenuBuilder::getBreadCrumbs()
{% set item = knp_menu_get('main') %}
{{ knp_menu_render(item) }}
{% block breadcrumbs %}
{% set breadcrumbs = knp_menu_get('breadcrumbs', [], {'request': app.request, 'menu': item }) %}
{{ dump(breadcrumbs) }}
{% endblock %}
Why it doesn't accepts "item" variable?
Since version 2.0, getBreadcrumbsArray has been moved to Knp\Menu\Util\MenuManipulator.
Possible workout to this solution is to create a twig extension:
<?php
namespace Kimwild\CommonBundle\Twig;
use Knp\Menu\Util\MenuManipulator;
use Knp\Menu\ItemInterface;
class MenuManipulatorExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('menu_manipulator', array($this, 'menuManipulator')),
);
}
public function menuManipulator(ItemInterface $item)
{
$manipulator = new MenuManipulator();
return $manipulator->getBreadcrumbsArray($item);
}
public function getName()
{
return 'menu_manipulator';
}
}
Register twig extension:
kimwild_common.menu_manipulator_extension:
class: Kimwild\CommonBundle\Twig\MenuManipulatorExtension
public: false
tags:
- { name: twig.extension }
In breadcrumb.html.twig:
{% block root %}
{%- for link in menu_manipulator(item) %}
/* whatever you want to do ... */
{%- endfor %}
{% endblock %}
The Knp\Menu\MenuItem class has a getBreadcrumbsArray() method. It should return an array of items in the current active menu trail. If you are on an earlier version of KnpMenu (<= 1.1.2, I think), the returned array will be in the form of label => uri. Otherwise, it will be an array with each item having keys label, uri, and item.
To find the current menu item, you'll probably want to create a method in your controller (or somewhere else, if it makes more sense for your project) that looks something like this:
public function getCurrentMenuItem($menu)
{
foreach ($menu as $item) {
if ($item->isCurrent()) {
return $item;
}
if ($item->getChildren() && $current_child = $this->getCurrentMenuItem($item)) {
return $current_child;
}
}
return null;
}
From there, you can call getBreadcrumbsArray() on the returned value:
$this->getCurrentMenuItem($your_menu)->getBreadcrumbsArray();
I guess what I would do ultimately is create a Twig extension that registers a breadcrumbs global, and put the getCurrentMenuItem() method in there. That way, you can have the breadcrumb variable in all of your templates without having to manually render it in each controller.
Source: https://github.com/KnpLabs/KnpMenu/blob/master/src/Knp/Menu/MenuItem.php#L544.
Since KnpMenu 2.1, there is a new twig function: knp_menu_get_breadcrumbs_array
You can take a look at my gist: https://gist.github.com/fsevestre/b378606c4fd23814278a
I added a new twig function knp_menu_get_current_item, which retrieve the current menu item and work fine with the knp_menu_get_breadcrumbs_array function.
--
Edit:
With KnpMenu 2.2, you can now do:
<ol class="breadcrumb">
{% for breadcrumb_item in knp_menu_get_breadcrumbs_array(knp_menu_get_current_item('main')) %}
{% if not loop.last %}
<li>{{ breadcrumb_item.label }}</li>
{% else %}
<li class="active">{{ breadcrumb_item.label }}</li>
{% endif %}
{% endfor %}
</ol>
https://github.com/KnpLabs/KnpMenu/blob/master/doc/02-Twig-Integration.markdown#functions
The knp_menu_get_current_item('main') Twig function will retrieve the current menu item, for the main menu.

Categories