소스 검색

Merge filter and batch action.

Thomas Rabaix 14 년 전
부모
커밋
d79d99bdea
6개의 변경된 파일64개의 추가작업 그리고 69개의 파일을 삭제
  1. 5 4
      Admin/Admin.php
  2. 17 40
      Controller/CRUDController.php
  3. 5 0
      Datagrid/ORM/ProxyQuery.php
  4. 2 2
      Model/ModelManagerInterface.php
  5. 32 11
      Model/ORM/ModelManager.php
  6. 3 12
      Resources/views/CRUD/base_list.html.twig

+ 5 - 4
Admin/Admin.php

@@ -534,15 +534,16 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         return $this->listFieldDescriptions;
     }
-    
+
     /**
      * Get parameters that are currently bound to the filter.
-     * 
+     *
      * @return array
      */
     public function getFilterParameters()
     {
         $parameters = array();
+
         // build the values array
         if ($this->hasRequest()) {
             $parameters = array_merge(
@@ -556,6 +557,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
                 $parameters[$this->getParentAssociationMapping()] = $this->request->get($this->getParent()->getIdParameter());
             }
         }
+
         return $parameters;
     }
 
@@ -768,7 +770,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         return $actions;
     }
-    
+
     public function getFilterActions()
     {
         return array();
@@ -829,7 +831,6 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
         $collection->add('list');
         $collection->add('create');
         $collection->add('batch');
-        $collection->add('filter');
         $collection->add('edit', $this->getRouterIdParameter().'/edit');
         $collection->add('delete', $this->getRouterIdParameter().'/delete');
         $collection->add('view', $this->getRouterIdParameter().'/view');

+ 17 - 40
Controller/CRUDController.php

@@ -138,17 +138,17 @@ class CRUDController extends Controller
      * @param array $idx
      * @return \Symfony\Component\HttpFoundation\RedirectResponse
      */
-    public function batchActionDelete($idx)
+    public function batchActionDelete($query)
     {
         if (false === $this->admin->isGranted('DELETE')) {
             throw new AccessDeniedException();
         }
 
         $modelManager = $this->admin->getModelManager();
-        $modelManager->batchDelete($this->admin->getClass(), $idx);
+        $modelManager->batchDelete($this->admin->getClass(), $query);
 
         // todo : add confirmation flash var
-        return new RedirectResponse($this->admin->generateUrl('list'));
+        return new RedirectResponse($this->admin->generateUrl('list', $this->admin->getFilterParameters()));
     }
 
     public function deleteAction($id)
@@ -245,38 +245,6 @@ class CRUDController extends Controller
 
         return new RedirectResponse($url);
     }
-    
-    /**
-     * Execute a filter action, an action performed on all filter entries of a datagrid.
-     * 
-     * @return Response
-     */
-    public function filterAction()
-    {
-        if ($this->get('request')->getMethod() != 'POST') {
-           throw new \RuntimeException('invalid request type, POST expected');
-        }        
-        
-        $action = $this->get('request')->get('action');
-        
-        if (!array_key_exists($action, $this->admin->getFilterActions())) {
-            throw new \RuntimeException(sprintf('The `%s` batch action is not defined', $action));
-        }
-        
-        // execute the action, filterActionXxxxx
-        $action = \Sonata\AdminBundle\Admin\BaseFieldDescription::camelize($action);
-
-        $final_action = sprintf('filterAction%s', ucfirst($action));
-        if (!method_exists($this, $final_action)) {
-            throw new \RuntimeException(sprintf('A `%s::%s` method must be created', get_class($this), $final_action));
-        }
-        
-        $grid = $this->admin->getDatagrid();
-        $grid->buildPager();
-        $query = $grid->getQuery();
-
-        return call_user_func(array($this, $final_action), $query);
-    }
 
     /**
      * return the Response object associated to the batch action
@@ -290,13 +258,14 @@ class CRUDController extends Controller
            throw new \RuntimeException('invalid request type, POST expected');
         }
 
-        $action = $this->get('request')->get('action');
-        $idx    = $this->get('request')->get('idx');
+        $action       = $this->get('request')->get('action');
+        $idx          = $this->get('request')->get('idx');
+        $all_elements = $this->get('request')->get('all_elements', false);
 
-        if (count($idx) == 0) { // no item selected
+        if (count($idx) == 0 && !$all_elements) { // no item selected
             // todo : add flash information
 
-            return new RedirectResponse($this->admin->generateUrl('list'));
+            return new RedirectResponse($this->admin->generateUrl('list', $this->admin->getFilterParameters()));
         }
 
         if (!array_key_exists($action, $this->admin->getBatchActions())) {
@@ -311,7 +280,15 @@ class CRUDController extends Controller
             throw new \RuntimeException(sprintf('A `%s::%s` method must be created', get_class($this), $final_action));
         }
 
-        return call_user_func(array($this, $final_action), $idx);
+        $datagrid = $this->admin->getDatagrid();
+        $datagrid->buildPager();
+        $query = $datagrid->getQuery();
+
+        if (!$all_elements && count($idx) > 0) {
+            $this->admin->getModelManager()->addIdentifiersToQuery($this->admin->getClass(), $query, $idx);
+        }
+
+        return call_user_func(array($this, $final_action), $query);
     }
 
     /**

+ 5 - 0
Datagrid/ORM/ProxyQuery.php

@@ -123,4 +123,9 @@ class ProxyQuery implements ProxyQueryInterface
     {
         $this->queryBuilder = clone $this->queryBuilder;
     }
+
+    public function getQueryBuilder()
+    {
+      return $this->queryBuilder;
+    }
 }

+ 2 - 2
Model/ModelManagerInterface.php

@@ -13,10 +13,10 @@ namespace Sonata\AdminBundle\Model;
 
 use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
 use Sonata\AdminBundle\Datagrid\DatagridInterface;
+use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
 
 interface ModelManagerInterface
 {
-
     /**
      * Returns true if the model has a relation
      *
@@ -81,7 +81,7 @@ interface ModelManagerInterface
      * @param array $idx
      * @return void
      */
-    function batchDelete($class, $idx);
+    function batchDelete($class, ProxyQueryInterface $queryProxy);
 
     /**
      * @abstract

+ 32 - 11
Model/ORM/ModelManager.php

@@ -15,13 +15,14 @@ use Sonata\AdminBundle\Model\ModelManagerInterface;
 use Sonata\AdminBundle\Admin\ORM\FieldDescription;
 use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
 use Sonata\AdminBundle\Datagrid\DatagridInterface;
+use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
 use Doctrine\ORM\EntityManager;
 use Doctrine\ORM\QueryBuilder;
+
 use Symfony\Component\Form\Exception\PropertyAccessDeniedException;
 
 class ModelManager implements ModelManagerInterface
 {
-
     protected $entityManager;
 
     /**
@@ -199,6 +200,26 @@ class ModelManager implements ModelManagerInterface
         return implode('-', $values);
     }
 
+    public function addIdentifiersToQuery($class, ProxyQueryInterface $queryProxy, array $idx)
+    {
+        $fieldNames = $this->getIdentifierFieldNames($class);
+        $qb = $queryProxy->getQueryBuilder();
+
+        $prefix = uniqid();
+        foreach ($idx as $pos => $id) {
+            $ids     = explode('-', $id);
+
+            $ands = array();
+            foreach ($fieldNames as $posName => $name) {
+                $parameterName = sprintf('field_%s_%s_%d', $prefix, $name, $pos);
+                $ands[] = sprintf('%s.%s = :%s', $qb->getRootAlias(), $name, $parameterName);
+                $qb->setParameter($parameterName, $ids[$posName]);
+            }
+
+            $qb->orWhere(implode(' AND ', $ands));
+        }
+    }
+
     /**
      * Deletes a set of $class identified by the provided $idx array
      *
@@ -206,20 +227,20 @@ class ModelManager implements ModelManagerInterface
      * @param array $idx
      * @return void
      */
-    public function batchDelete($class, $idx)
+    public function batchDelete($class, ProxyQueryInterface $queryProxy)
     {
-        $queryBuilder = $this->createQuery($class, 'o');
-        $objects = $queryBuilder
-            ->select('o')
-            ->add('where', $queryBuilder->expr()->in('o.id', $idx))
-            ->getQuery()
-            ->execute();
-
-        foreach ($objects as $object) {
-            $this->entityManager->remove($object);
+        $i = 0;
+        foreach ($queryProxy->getQuery()->iterate() as $pos => $object) {
+            $this->entityManager->remove($object[0]);
+
+            if ((++$i % 20) == 0) {
+                $this->entityManager->flush();
+                $this->entityManager->clear();
+            }
         }
 
         $this->entityManager->flush();
+        $this->entityManager->clear();
     }
 
     /**

+ 3 - 12
Resources/views/CRUD/base_list.html.twig

@@ -26,7 +26,7 @@ file that was distributed with this source code.
 {% block list_table %}
     {% set batchactions = admin.batchactions %}
     {% if admin.datagrid.results|length > 0 %}
-        <form action="{{ admin.generateUrl('batch') }}" method="POST" >
+        <form action="{{ admin.generateUrl('batch', admin.filterParameters) }}" method="POST" >
             <table>
                 {% block table_header %}
                     <tr class="sonata-ba-list-field-header">
@@ -119,6 +119,8 @@ file that was distributed with this source code.
                             <option value="{{ action }}">{{ label }}</option>
                         {% endfor %}
                     </select>
+                    <input type="checkbox" name="all_elements" id="execute_on_matching"  />
+                    <label for="execute_on_matching">{% trans from 'SonataAdminBundle' %}all_elements{% endtrans %}</label>
                     <input type="submit" value="{% trans from 'SonataAdminBundle' %}btn_batch{% endtrans %}" />
                 </div>
             {% endif %}
@@ -143,17 +145,6 @@ file that was distributed with this source code.
 
             <a href="{{ admin.generateUrl('list') }}">{% trans from 'SonataAdminBundle' %}link_reset_filter{% endtrans %}</a>
         </form>
-    
-        {% if admin.filterActions %}
-        <form class="sonata-filter-action-form" action="{{ admin.generateUrl('filter') }}?{% for k,v in admin.filterParameters %}&{{k}}={{v}}{% endfor %}" method="POST">
-            <select name="action">
-                {% for action, label in admin.filterActions %}
-                    <option value="{{ action }}">{{ label }}</option>
-                {% endfor %}
-            </select>
-            <input type="submit" value="{% trans from 'SonataAdminBundle' %}btn_batch{% endtrans %}" />
-        </form>
-        {% endif %}
     {% endif %}
 {% endblock %}