Browse Source

convert filter

Thomas Rabaix 14 years ago
parent
commit
c37eb9ba7c

+ 9 - 1
Builder/ORM/DatagridBuilder.php

@@ -19,12 +19,15 @@ use Sonata\AdminBundle\Datagrid\Datagrid;
 use Sonata\AdminBundle\Datagrid\ORM\Pager;
 use Sonata\AdminBundle\Datagrid\ORM\ProxyQuery;
 use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
+use Symfony\Component\Form\FormFactory;
 
 use Doctrine\ORM\Mapping\ClassMetadataInfo;
 
 class DatagridBuilder implements DatagridBuilderInterface
 {
 
+    protected $formFactory;
+
     /**
      * todo: put this in the DIC
      *
@@ -45,6 +48,11 @@ class DatagridBuilder implements DatagridBuilderInterface
         'callback'   =>  'Sonata\\AdminBundle\\Filter\\ORM\\CallbackFilter',
     );
 
+    public function __construct(FormFactory $formFactory)
+    {
+        $this->formFactory = $formFactory;
+    }
+
     /**
      * @throws \RuntimeException
      * @param \Sonata\AdminBundle\Admin\AdminInterface $admin
@@ -157,7 +165,6 @@ class DatagridBuilder implements DatagridBuilderInterface
     public function addFilter(DatagridInterface $datagrid, FieldDescriptionInterface $fieldDescription)
     {
         if (!$fieldDescription->getType()) {
-
             return false;
         }
 
@@ -201,6 +208,7 @@ class DatagridBuilder implements DatagridBuilderInterface
             $query,
             $admin->getList(),
             new Pager,
+            $this->formFactory,
             $values
         );
     }

+ 13 - 7
Datagrid/Datagrid.php

@@ -14,6 +14,7 @@ namespace Sonata\AdminBundle\Datagrid;
 use Sonata\AdminBundle\Datagrid\PagerInterface;
 use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
 use Sonata\AdminBundle\Filter\FilterInterface;
+use Symfony\Component\Form\FormFactory;
 
 class Datagrid implements DatagridInterface
 {
@@ -34,12 +35,15 @@ class Datagrid implements DatagridInterface
 
     protected $query;
 
-    public function __construct(ProxyQueryInterface $query, ListCollection $columns, PagerInterface $pager, array $values = array())
+    protected $formFactory;
+
+    public function __construct(ProxyQueryInterface $query, ListCollection $columns, PagerInterface $pager, FormFactory $formFactory, array $values = array())
     {
         $this->pager    = $pager;
         $this->query    = $query;
         $this->values   = $values;
         $this->columns  = $columns;
+        $this->formFactory = $formFactory;
     }
 
     /**
@@ -65,10 +69,10 @@ class Datagrid implements DatagridInterface
         }
 
         foreach ($this->getFilters() as $name => $filter) {
-            $filter->apply(
-                $this->query,
-                isset($this->values[$name]) ? $this->values[$name] : null
-            );
+            $value = isset($this->values[$name]) ? $this->values[$name] : null;
+
+            $filter->getField()->setData($value);
+            $filter->apply($this->query, $value);
         }
 
         $this->query->setSortBy(isset($this->values['_sort_by']) ? $this->values['_sort_by'] : null);
@@ -83,11 +87,13 @@ class Datagrid implements DatagridInterface
 
     /**
      * @param \Sonata\AdminBundle\Filter\FilterInterface $filter
-     * @return \Sonata\AdminBundle\Filter\FilterInterface
+     * @return void
      */
     public function addFilter(FilterInterface $filter)
     {
-        return $this->filters[$filter->getName()] = $filter;
+        $filter->defineFieldBuilder($this->formFactory);
+
+        $this->filters[$filter->getName()] = $filter;
     }
 
     public function getFilters()

+ 2 - 0
DependencyInjection/SonataAdminExtension.php

@@ -71,6 +71,8 @@ class SonataAdminExtension extends Extension
 
         // register filter builder
         $definition = new Definition('Sonata\AdminBundle\Builder\ORM\DatagridBuilder');
+        $definition->addArgument(new Reference('form.factory'));
+
         $container->setDefinition('sonata_admin.builder.orm_datagrid', $definition);
 
         // registers crud action

+ 30 - 24
Filter/Filter.php

@@ -13,13 +13,11 @@ namespace Sonata\AdminBundle\Filter;
 
 use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
 use Sonata\AdminBundle\Filter\FilterInterface;
-use Symfony\Component\Form\Configurable;
 use Doctrine\ORM\QueryBuilder;
 
-abstract class Filter extends Configurable implements FilterInterface
+abstract class Filter implements FilterInterface
 {
-
-    protected $description = array();
+    protected $fieldDescription = array();
 
     protected $name = null;
 
@@ -27,44 +25,52 @@ abstract class Filter extends Configurable implements FilterInterface
 
     protected $value = null;
 
+    protected $options = array();
+
     public function __construct(FieldDescriptionInterface $fieldDescription)
     {
         $this->name         = $fieldDescription->getName();
-        $this->description  = $fieldDescription;
-
-        parent::__construct($fieldDescription->getOption('filter_options', array()));
+        $this->fieldDescription  = $fieldDescription;
+        $this->options      = array_replace(
+            $this->getDefaultOptions(),
+            $this->fieldDescription->getOption('filter_options', array())
+        );
 
-        $this->field        = $this->getFormField();
     }
 
-    /**
-     * get the object description
-     *
-     * @return array
-     */
-    public function getDescription()
+    public function getName()
     {
-        return $this->description;
+        return $this->name;
     }
 
-    public function setName($name)
+    public function getField()
     {
-        $this->name = $name;
+        if (!$this->field) {
+            throw new \RuntimeException('No field attached');
+        }
+
+        return $this->field;
     }
 
-    public function getName()
+    /**
+     * @return \Sonata\AdminBundle\Admin\FieldDescriptionInterface
+     */
+    public function getFieldDescription()
     {
-        return $this->name;
+        return $this->fieldDescription;
     }
 
-    public function setField($field)
+    public function getDefaultOptions()
     {
-        $this->field = $field;
+        return array();
     }
 
-    public function getField()
+    public function getOption($name, $default = null)
     {
-        return $this->field;
-    }
+        if (array_keys($this->options, $name)) {
+            return $this->options[$name];
+        }
 
+        return $default;
+    }
 }

+ 36 - 4
Filter/FilterInterface.php

@@ -11,6 +11,8 @@
 
 namespace Sonata\AdminBundle\Filter;
 
+use Symfony\Component\Form\FormFactory;
+
 interface FilterInterface
 {
     /**
@@ -26,17 +28,47 @@ interface FilterInterface
     function filter($queryBuilder, $alias, $field, $value);
 
     /**
-     * Get the related form field filter
+     * Define the related field builder
      *
      * @abstract
-     * @return Field
+     * @param \Symfony\Component\Form\FormFactory
+     * @return void
      */
-    function getFormField();
+    function defineFieldBuilder(FormFactory $formFactory);
 
     /**
      * Returns the filter name
      * @abstract
-     * @return void
+     * @return string
      */
     function getName();
+
+    /**
+     * Returns the formBuilder instance
+     *
+     * @abstract
+     * @return \Symfony\Component\Form\FormBuilder
+     */
+    function getField();
+
+    /**
+     * @abstract
+     * @return array
+     */
+    function getDefaultOptions();
+
+    /**
+     * @abstract
+     * @param string $name
+     * @param null $default
+     * @return void
+     */
+    function getOption($name, $default = null);
+
+    /**
+     * @abstract
+     * @return \Sonata\AdminBundle\Admin\FieldDescriptionInterface
+     */
+    function getFieldDescription();
+
 }

+ 7 - 16
Filter/ORM/BooleanFilter.php

@@ -11,16 +11,14 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Sonata\AdminBundle\Admin\FieldDescription;
 use Doctrine\ORM\QueryBuilder;
+use Symfony\Component\Form\FormFactory;
 
 class BooleanFilter extends Filter
 {
-
     public function filter($queryBuilder, $alias, $field, $value)
     {
-
-        if ($this->getField()->isMultipleChoice()) {
+        if ($this->getField()->getAttribute('multiple')) {
 
             $values = array();
             foreach ($value as $v) {
@@ -34,7 +32,7 @@ class BooleanFilter extends Filter
             if (count($values) == 0) {
                 return;
             }
-            
+
             $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s',
                 $alias,
                 $field
@@ -46,21 +44,18 @@ class BooleanFilter extends Filter
                 return;
             }
 
-            $value      = $value == 'true' ? 1 : 0;
-            
             $queryBuilder->andWhere(sprintf('%s.%s = :%s',
                 $alias,
                 $field,
                 $this->getName()
             ));
 
-            $queryBuilder->setParameter($this->getName(), $value);
+            $queryBuilder->setParameter($this->getName(), $value == 'true' ? 1 : 0);
         }
     }
 
-    public function getFormField()
+    public function defineFieldBuilder(FormFactory $formFactory)
     {
-
         $options = array(
             'choices' => array(
                 'all'   => 'all',
@@ -70,12 +65,8 @@ class BooleanFilter extends Filter
             'required' => false
         );
 
-        $options = array_merge($options, $this->description->getOption('filter_field_options', array()));
+        $options = array_merge($options, $this->getFieldDescription()->getOption('filter_field_options', array()));
 
-        return new \Symfony\Component\Form\ChoiceField(
-            $this->getName(),
-            $options
-        );
+        $this->field = $formFactory->createNamedBuilder('choice', $this->getName(), null, $options);
     }
-
 }

+ 12 - 12
Filter/ORM/CallbackFilter.php

@@ -11,12 +11,11 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Sonata\AdminBundle\Admin\FieldDescription;
+use Symfony\Component\Form\FormFactory;
 use Doctrine\ORM\QueryBuilder;
 
 class CallbackFilter extends Filter
 {
-
     protected function association($queryBuilder, $value)
     {
         return array($queryBuilder->getRootAlias(), false);
@@ -24,6 +23,9 @@ class CallbackFilter extends Filter
 
     public function filter($queryBuilder, $alias, $field, $value)
     {
+        if (is_callable($this->getOption('filter'))) {
+            throw new \RuntimeException('Please provide a valid callback option');
+        }
 
         call_user_func($this->getOption('filter'), $queryBuilder, $alias, $field, $value);
     }
@@ -33,24 +35,22 @@ class CallbackFilter extends Filter
      *        'type'           => 'callback',
      *        'filter_options' => array(
      *           'filter'  => array($this, 'getCustomFilter'),
-     *           'field'   => array($this, 'getCustomField')
+     *           'type'    => 'type_name'
      *       )
      *    );
      *
      * @return void
      */
-    protected function configure()
+    public function getDefaultOptions()
     {
-
-        $this->addRequiredOption('filter');
-        $this->addRequiredOption('field');
-
-        parent::configure();
+        return array(
+            'filter' => null,
+            'type'   => 'text',
+        );
     }
 
-    public function getFormField()
+    public function defineFieldBuilder(FormFactory $formFactory)
     {
-
-        return call_user_func($this->getOption('field'), $this);
+        return $formFactory->createNamedBuilder($this->getOption('type'), $this->getName(), null);
     }
 }

+ 6 - 9
Filter/ORM/ChoiceFilter.php

@@ -11,16 +11,14 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Sonata\AdminBundle\Admin\FieldDescription;
+use Symfony\Component\Form\FormFactory;
 use Doctrine\ORM\QueryBuilder;
 
 class ChoiceFilter extends Filter
 {
-
     public function filter($queryBuilder, $alias, $field, $value)
     {
-        if ($this->getField()->isMultipleChoice()) {
-
+        if ($this->getField()->getAttribute('multiple')) {
             if (in_array('all', $value)) {
                 return;
             }
@@ -50,11 +48,10 @@ class ChoiceFilter extends Filter
         }
     }
 
-    public function getFormField()
+    public function defineFieldBuilder(FormFactory $formFactory, $value = null)
     {
-        return new \Symfony\Component\Form\ChoiceField(
-            $this->getName(),
-            $this->description->getOption('filter_field_options', array('required' => false))
-        );
+        $options = $this->getFieldDescription()->getOption('filter_field_options', array('required' => false));
+
+        $this->field = $formFactory->createNamedBuilder('choice', $this->getName(), $value, $options);
     }
 }

+ 6 - 7
Filter/ORM/Filter.php

@@ -13,6 +13,7 @@ namespace Sonata\AdminBundle\Filter\ORM;
 
 use Sonata\AdminBundle\Filter\Filter as BaseFilter;
 use Doctrine\ORM\Mapping\ClassMetadataInfo;
+use Symfony\Component\Form\FormBuilder;
 
 abstract class Filter extends BaseFilter
 {
@@ -21,18 +22,16 @@ abstract class Filter extends BaseFilter
     {
         $this->value = $value;
 
-        $this->field->submit($value);
+        list($alias, $field) = $this->association($queryBuilder, $value);
 
-        list($alias, $field) = $this->association($queryBuilder, $this->field->getData());
-
-        $this->filter($queryBuilder, $alias, $field, $this->field->getData());
+        $this->filter($queryBuilder, $alias, $field, $value);
     }
 
     protected function association($queryBuilder, $value)
     {
-        if ($value && $this->description->getType() == ClassMetadataInfo::MANY_TO_MANY) {
+        if ($value && $this->getFieldDescription()->getType() == ClassMetadataInfo::MANY_TO_MANY) {
             $queryBuilder->leftJoin(
-                sprintf('%s.%s', $queryBuilder->getRootAlias(), $this->description->getFieldName()),
+                sprintf('%s.%s', $queryBuilder->getRootAlias(), $this->getFieldDescription()->getFieldName()),
                 $this->getName()
             );
 
@@ -40,6 +39,6 @@ abstract class Filter extends BaseFilter
             return array($this->getName(), 'id');
         }
 
-        return array($queryBuilder->getRootAlias(), $this->description->getFieldName());
+        return array($queryBuilder->getRootAlias(), $this->getFieldDescription()->getFieldName());
     }
 }

+ 10 - 10
Filter/ORM/IntegerFilter.php

@@ -12,6 +12,7 @@
 namespace Sonata\AdminBundle\Filter\ORM;
 
 use Doctrine\ORM\QueryBuilder;
+use Symfony\Component\Form\FormFactory;
 
 class IntegerFilter extends Filter
 {
@@ -34,19 +35,18 @@ class IntegerFilter extends Filter
         $queryBuilder->setParameter($this->getName(), (int)$value);
     }
 
-    protected function configure()
+    public function getDefaultOptions()
     {
-        $this->addOption('operator', '=');
-        $this->addOption('format', '%d');
-
-        parent::configure();
+        return array(
+            'operator' => '=',
+            'format'   => '%d'
+        );
     }
 
-   public function getFormField()
+   public function defineFieldBuilder(FormFactory $formFactory)
    {
-       return new \Symfony\Component\Form\TextField(
-           $this->getName(),
-           $this->description->getOption('filter_field_options', array('required' => false))
-       );
+       $options = $this->fieldDescription->getOption('filter_field_options', array('required' => false));
+
+       $this->field = $formFactory->createNamedBuilder('text', $this->getName(), null, $options);
    }
 }

+ 9 - 11
Filter/ORM/StringFilter.php

@@ -11,7 +11,7 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Sonata\AdminBundle\Admin\FieldDescription;
+use Symfony\Component\Form\FormFactory;
 use Doctrine\ORM\QueryBuilder;
 
 class StringFilter extends Filter
@@ -19,7 +19,6 @@ class StringFilter extends Filter
 
     public function filter($queryBuilder, $alias, $field, $value)
     {
-
         if ($value == null) {
             return;
         }
@@ -36,18 +35,17 @@ class StringFilter extends Filter
         $queryBuilder->setParameter($this->getName(), $value);
     }
 
-    protected function configure()
+    public function getDefaultOptions()
     {
-        $this->addOption('format', '%%%s%%');
-
-        parent::configure();
+        return array(
+            'format'   => '%%%s%%'
+        );
     }
 
-   public function getFormField()
+   public function defineFieldBuilder(FormFactory $formFactory)
    {
-       return new \Symfony\Component\Form\TextField(
-           $this->getName(),
-           $this->description->getOption('filter_field_options', array('required' => false))
-       );
+       $options = $this->fieldDescription->getOption('filter_field_options', array('required' => false));
+
+       $this->field = $formFactory->createNamedBuilder('text', $this->getName(), null, $options);
    }
 }

+ 5 - 5
Resources/views/CRUD/base_filter_field.html.twig

@@ -11,15 +11,15 @@ file that was distributed with this source code.
 
 <div>
     {% block label %}
-        {% if filter.description.options.name is defined %}
-            {{ form_label(filter.field, filter.description.options.name) }}
+        {% if filter.fielddescription.options.name is defined %}
+            {{ form_label(filter_form, filter.fielddescription.options.name) }}
         {% else %}
-            {{ form_label(filter.field) }}
+            {{ form_label(filter_form) }}
         {% endif %}
         <br />
     {% endblock %}
 
-    <div class="sonata-ba-field{% if filter.field.haserrors %} sonata-ba-field-error"{% endif %}">
-        {% block field %}{{ form_field(filter.field) }}{% endblock %}
+    <div class="sonata-ba-field{% if filter_form.vars.errors %} sonata-ba-field-error"{% endif %}">
+        {% block field %}{{ form_widget(filter_form) }}{% endblock %}
     </div>
 </div>

+ 3 - 2
Twig/Extension/SonataAdminExtension.php

@@ -127,12 +127,13 @@ class SonataAdminExtension extends \Twig_Extension
      */
     public function renderFilterElement(FilterInterface $filter, array $params = array())
     {
-        $description = $filter->getDescription();
+        $description = $filter->getFieldDescription();
 
         $template = $this->environment->loadTemplate($description->getTemplate());
 
         return $template->render(array_merge($params, array(
-            'filter' => $filter
+            'filter'        => $filter,
+            'filter_form'   => $filter->getField()->getForm()->createView()
         )));
     }