2

I am new to symfony/doctrine and when setting up my first table and query I am struggling with the best way to output results in Twig.

So, I have this method on \AppBundle\Controller\BrandsController

    public function showAction($brand)
{

   $product = $this->getDoctrine()
       ->getRepository('AppBundle:Brands')
       ->findOneByBrand($brand);

   if (!$product) {
       throw $this->createNotFoundException(
           'No product found for id '.$brand
       );
   }
    return $this->render('brands/brands.html.twig', [
        'product' => $product
    ]);
}

This produces an object like below, which I cannot iterate over.

Brands {#459 ▼
-brand_id: 24
-brand: "Ford"
-active: "Y"
-img_logo: "/img/brand/ford.png"
-img_logo_small: "/img/brand/ford_20.png"
-img_logo_big: "/img/brand/ford-big.png"
}

Of course I can create a query like below, but that negates the benefit of the findBy() method:

$repository = $this->getDoctrine()
->getRepository('AppBundle:Brands');
$query = $repository->createQueryBuilder('p')
    ->where('p.brand = :brand')
    ->setParameter('brand', $brand)
    ->getQuery();
    $product = $query->getSingleResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);

I found similar questions, like this one, but they mess up with the array keys by giving a array that looks like:

array:6 [▼
"\x00AppBundle\Entity\Brands\x00brand_id" => 24
"\x00AppBundle\Entity\Brands\x00brand" => "Ford"
"\x00AppBundle\Entity\Brands\x00active" => "Y"
"\x00AppBundle\Entity\Brands\x00img_logo" => "/img/brand/ford.png"
"\x00AppBundle\Entity\Brands\x00img_logo_small" => "/img/brand/ford_20.png"
"\x00AppBundle\Entity\Brands\x00img_logo_big" => "/img/brand/ford-big.png"
]

By the way, that's the simple version of the code on brands/brands.html.twig:

 {% for item in product %}
      <p> This is my   {{ item }}</p>
 {% endfor %}

Is there a clean way to do it?

Thanks

Community
  • 1
  • 1
BernardA
  • 1,391
  • 19
  • 48
  • you dont need to convert it to an array, to output the object in you'r twig file , just {{product.id}} {{product.brand}} etc.. – famas23 May 13 '17 at 10:28
  • @Bhs. That would be awkward, having to mention each key. This should use a for loop and iterate over the object/array like: {% for item in product %}

    This is my {{ item }}

    {% endfor %}
    – BernardA May 13 '17 at 10:32
  • you need to structure your array from your object to iterate it ,take a look here http://stackoverflow.com/questions/7093515/can-i-iterate-over-an-entitys-properties-in-doctrine2 – famas23 May 13 '17 at 10:52
  • Also here on github ther's a serlize script : https://github.com/borisguery/bgylibrary/blob/master/library/Bgy/Doctrine/EntitySerializer.php – famas23 May 13 '17 at 10:58
  • @Bhs, the serializer script worked for me. Put this up as a proper answer and I will accept it, thanks. – BernardA May 13 '17 at 15:38
  • Oh thank you BernardA , Happy to help you ,and feel free to edit my answer – famas23 May 13 '17 at 19:52

2 Answers2

0

The idea is to use Entity Serializer Doctrine Script , look to the link below : https://github.com/borisguery/bgylibrary/blob/master/library/Bgy/Doctrine/EntitySerializer.php
Just copy the script into a new class : EntitySerializer.php , under AppBundle\Controller , then in your BrandsController class:

$em = $this->getDoctrine()->getManager(); 
$product = $em->getRepository('AppBundle:Brands') ->findOneByBrand($brand); 
$serializer = new EntitySerializer($em);
$product = $serializer->toArray($product);

and finnally you can easily iterate the array :

foreach ($array as $key => $value) {
    echo 'the key is '.$key.'<br>';
    echo 'the value is '.$value;
}
famas23
  • 2,072
  • 4
  • 17
  • 53
  • The idea was to use the findby() not the query builder. So, I would skip your introduction and just add some code like $em = $this->getDoctrine()->getManager(); $product = $em->getRepository('AppBundle:Brands') ->findOneByBrand($brand); $serializer = new EntitySerializer($em); $product = $serializer->toArray($product); – BernardA May 14 '17 at 17:17
  • Fixed ,findoneBy or findByBrand ,at the end we need to return an object to convert it to an array . – famas23 May 14 '17 at 17:23
-2

General... It's kinda bad idea to iterate through your product in twig like an array. Just because it's matter of time till you'll need more controll like show/do this if product is active or not... and so on. So pretty soon you'll have to do somthing like this (just an wild example of possible usecase...)

{% if product|default %}

  {# if logo isn't there or empty or similar use path to no-logo.png as fallback  #}
  {% set _product_logo_path = product.img_logo|default('/assets/images/no-logo.png') %}

  {{ product.brand }} <img src="{{- _product_logo_path  -}}" title="blah blah" />

  {% if not product.isActive|default %}
   <span>currently unavailable</span>
  {% endif %}
{% endfi %}

Architectual...

You can use your repository for that kind of "manipulation"

something like :

in your controller:

$product = $this->getDoctrine()
       ->getRepository('AppBundle:Brands')
       ->findOneForViewByBrand($brand);


// concider to use instanceof since you expecting Brands object
// if not stay with !$product
if( false === $product instanceof Brands )
{
   // not found exception..
}

in your Repo-Class

public function findOneForViewByBrand( $brand )
{

  // you ca make use of PARTIAL SELECTS
  // NOTE: if you use PARTIAL selects you have to select at least id, like PARTIAL p.{brand_id}

  $query = $this->createQueryBuilder('p')
    ->select('PARTIAL p.{brand_id, brand, active, img_logo, img_logo_small, img_logo_big}')
    ->where('p.brand = :brand')
    ->setParameter('brand', $brand)
    ->getQuery();


  // If found you'll get a Brand BUT ONLY field in curly brackets will be populated with data, others will be just NULL
  return $query->getOneOrNullResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY); 


}

and then in your twig

{% for fieldName, fieldValue in product %}
      {# should skip null values #}
      {% if fieldValue is defined and fieldValue is not empty % }
      <p> This is my   {{ fieldValue }}</p>
     {% endif %}
 {% endfor %}

About Partial Selects

P.S. code is untested and it's here so you can get an idea ;) I don't know what version of symfony you use and what version of doctrine is installed, so if one of mentioned methods doesn't exists - please don't be angry :)

V-Light
  • 3,065
  • 3
  • 25
  • 31
  • thanks @V-Light. I appreciate your overall insight but sometimes you just want to get this one simple thing working. If there is a tool like findby() one should be able to utilize without overcomplications. Although not optimal the serializer script mentioned by Bhs did the job and it will remain available on my app, and elsewhere, whenever this simple manipulation is required. – BernardA May 13 '17 at 15:45