12

I have the class categroies and class Products.

In my repository i have function

getProducts($categoryid,$location)

I need to loop in twig template like this

 {% for category in categories %}
    --{{ category.name }}--
      {% for product in getProducts(category.id,location) %}
     --{{ product.name }}--
    {% endfor %}
 {% endfor %}

or is there any better way for that

Mirage
  • 30,868
  • 62
  • 166
  • 261
  • Have you tried {% for item in product.items %} ? – Vitalii Zurian Aug 01 '12 at 07:00
  • I think you should create a Twig extension. Take a look at [this topic](http://stackoverflow.com/questions/8450465/fetching-data-through-a-custom-repository-in-a-twig-extension) – maxdec Aug 01 '12 at 07:05

4 Answers4

20

You shouldn't. Thats business logic, that should not appear in templates. One solution is to create a new action within a controller and in your template call

{% render '@MyBundle:Product:list' with {category: category.id} %}
KingCrunch
  • 128,817
  • 21
  • 151
  • 173
  • or can i make 2 dimensional array like `product[category][products]` in controller and then send that array in template – Mirage Aug 01 '12 at 07:12
  • @john110016 Or you create a OneToMany-Relationship between the category- and the product-entity ;) `for product in category.products`. Yes, there are multiple solutions, but calling the entity repository is not one of them. – KingCrunch Aug 01 '12 at 07:13
  • I already have the `onetomany` relationship but problem is how to apply the location filter , it shows all products if i do that – Mirage Aug 01 '12 at 07:20
  • @john110016 Good point. You could try a [Filter](http://twig.sensiolabs.org/doc/advanced.html) :) Should look like `for product in products|products_by_location(location)` or something like that. You can find information on how to implement them quite easy when usin s2 [in this article](http://martinsikora.com/how-to-make-twig-extension-for-symfony2) and in [official manual "How to write a custom Twig Extension"](http://symfony.com/doc/current/cookbook/templating/twig_extension.html). – KingCrunch Aug 01 '12 at 08:28
  • IIRC, rendering a controller can have a bad impact on performance. Can you please confirm that it won't be slower than passing the repository to the Twig template? – A.L Dec 26 '14 at 22:48
  • And if you use the `render` function, what does the Controller function called by `render` do? – A.L Dec 26 '14 at 22:57
7

It's a pretty old question, but I'm missing a really simple solution like this one.

It is possible to pass the repo object to twig and call the repo public methods from twig like so:

In your controller

$oCatRepo = $this->getDoctrine()->getManager()->getRepository('AppBundle:Categories');
....
return $this->render('product_list.html.twig', array('oCatRepo' => $oCatRepo));

And then in your twig template :

{{ oCatRepo.getProducts(category.id, location) }}

Im saying it's possible, many would argue that templates should only display data and let controllers gather the data. I personally don't mind letting my templates getting their data themselves.

10us
  • 1,622
  • 18
  • 13
1

I suspect that all you really need is a left join using a WITH expression. Something like:

class CategoryManager
{
    public function loadCategoriesProductsForLocation($location)
    {
        $qb = $this->em->->createQueryBuilder();

        $qb->addSelect('category');
        $qb->addSelect('product');

        $qb->from('MyBundleBundle:Category','category');

        $qb->leftJoin('category.products','product', 
            Expr\Join::WITH, $qb->expr()->eq('product.location', $location));

That will give you all the categories with their respective products for a given location.

Cerad
  • 48,157
  • 8
  • 90
  • 92
1

The solution is the other way around as how this is done right now. The Category entity should have a one-to-many relation. Take a look at http://symfony.com/doc/2.0/book/doctrine.html#entity-relationships-associations

The category Entity should then have an EntityCollection attribute called 'products'. In your template you then can solve this in the following way:

{% for category in categories %}
    --{{ category.name }}--
      {% for product in category.products %}
     --{{ product.name }}--
    {% endfor %}
 {% endfor %}
Rvanlaak
  • 2,971
  • 20
  • 40