tirenweb
tirenweb

Reputation: 31739

symfony2: multiple calls to an embbeded controller takes a lot of time

I have a long list of products in my backend (200). Depending if the product is associated to an order or not (someone bought the product), the user will be able to remove it or not from the list. So I have added this line for each product:

  {% for subitemColor in subitemsColor %}
   ...
   {%  render(controller('ProjectBackendBundle:SubitemColor:checkDeletion'), {'id': subitemColor.id}) %}
   ...
  {% endfor %}

So 200 lines like that are generated. Each of those lines will call this controller.

  public function checkDeletionAction(Request $request, $id)
  {
      $repository = $this->getDoctrine()->getRepository('ProjectBackendBundle:OrderSubitem');
      $orders = $repository->findBy(array('subitemColor' => $id)); 

      if (count($orders)) {
        return new Response("Product in order");
      } else {
        return new Response('<a href="' . $this->generateUrl('project_backend_subitem_color_remove', array('id' => $id)) . '">Remove</a>');
      }
  }

The problem: when the request is thrown, it takes to much time to show the results, maybe two minutes or more.. Is tha normal??

I know I could paginate the list and reduce the time, but I would like let the user to show the 200 results in just one page.

Upvotes: 0

Views: 112

Answers (2)

Jovan Perovic
Jovan Perovic

Reputation: 20201

Controller's action code:

public function mainAction(){
    $subitemsColor = ...;

    $ids = [];
    foreach ( $subitemsColor as $color ){
        $ids[] = $color->getId();
    }

    // Populate initial map with all zeros
    $countMap = array_values($ids, 0);

    /**
     * Returns array that look like this: 
     *  { 
     *      {id: id1, cnt: count1}, 
     *      {id: id2, cnt: count2}, 
     *      .... 
     *  }
     */
    $fetchedCountMap = $repository->findOrderCounts($ids);

    // Replace "0" with counted value from database
    foreach ( $orderCountMap as $count ){
        $countMap[$count['id']] = $count['cnt'];
    }

    return ['subitemsColor' => $subitemsColor, 'orderCountMap': $orderCountMap];
}

Repository method:

public function findOrderCounts(array $ids ){
    return $this->getEntityManager()
        ->createQuery("SELECT id, COUNT(e) AS cnt FROM AcmeBundle:Entity WHERE WHEER e.id IN (:ids)")
        ->setParameter('ids', $ids);
        ->getArrayResult();
}

Then it's just a matter of checking orderCountMap in twig and displaying either link or label if value is 0 or greater.

Upvotes: 0

Valentas
Valentas

Reputation: 2175

What I could recommend:

  1. initially retrieve all deletion statuses in primary controller and put in subitemsColor twig variable. Then iterate and use simple if-else clause. In short - move logic from checkDeletionAction() to twig.

  2. Use Repository as a service and mark it as lazy lazy="true"

  3. If You need only count of items - create Your own method in Repository with COUNT(*) and use $queryBuilder->getQuery()->getSingleScalarResult() to avoid full Object Hydration.

Upvotes: 1

Related Questions