Browse Source

add operator to all fields, update documentation

Thomas Rabaix 14 years ago
parent
commit
81bfb1da01

+ 3 - 2
Admin/Admin.php

@@ -559,7 +559,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
             // always force the parent value
             if ($this->isChild() && $this->getParentAssociationMapping()) {
-                $parameters[$this->getParentAssociationMapping()] = $this->request->get($this->getParent()->getIdParameter());
+                $parameters[$this->getParentAssociationMapping()] = array('value' => $this->request->get($this->getParent()->getIdParameter()));
             }
         }
 
@@ -593,7 +593,8 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
                 'field_type' => 'sonata_type_model_reference',
                 'field_options' => array(
                     'model_manager' => $this->getModelManager()
-                )
+                ),
+                'operator_type' => 'hidden'
             ));
         }
     }

+ 3 - 1
Datagrid/Datagrid.php

@@ -91,7 +91,9 @@ class Datagrid implements DatagridInterface
         }
 
         foreach ($this->getFilters() as $name => $filter) {
-            $this->formBuilder->add($name, $filter->getFieldType(), $filter->getFieldOptions());
+            list($type, $options) = $filter->getRenderSettings();
+
+            $this->formBuilder->add($name, $type, $options);
 
             $this->values[$name] = isset($this->values[$name]) ? $this->values[$name] : null;
             $filter->apply($this->query, $this->values[$name]);

+ 19 - 7
Datagrid/DatagridMapper.php

@@ -42,21 +42,33 @@ class DatagridMapper
 
     /**
      * @throws \RuntimeException
-     * @param mixed $name
-     * @param mixed $type
-     * @param array $fieldDescriptionOptions
+     * @param $name
+     * @param null $type
+     * @param array $filterOptions
+     * @param null $fieldType
+     * @param array $fieldOptions
      * @return DatagridMapper
      */
-    public function add($name, $type = null, array $fieldDescriptionOptions = array())
+    public function add($name, $type = null, array $filterOptions = array(), $fieldType = null, $fieldOptions = null)
     {
+        if (is_array($fieldOptions)) {
+            $filterOptions['field_options'] = $fieldOptions;
+        }
+
+        if ($fieldType) {
+            $filterOptions['field_type'] = $fieldType;
+        }
+
+        $filterOptions['field_name'] = isset($filterOptions['field_name']) ? $filterOptions['field_name'] : $name;
+
         if ($name instanceof FieldDescriptionInterface) {
             $fieldDescription = $name;
-            $fieldDescription->mergeOptions($fieldDescriptionOptions);
+            $fieldDescription->mergeOptions($filterOptions);
         } else if (is_string($name) && !$this->admin->hasFilterFieldDescription($name)) {
             $fieldDescription = $this->admin->getModelManager()->getNewFieldDescriptionInstance(
                 $this->admin->getClass(),
                 $name,
-                $fieldDescriptionOptions
+                $filterOptions
             );
         } else {
             throw new \RuntimeException('invalid state');
@@ -70,7 +82,7 @@ class DatagridMapper
 
     /**
      * @param string $name
-     * @return
+     * @return FilterInterface
      */
     public function get($name)
     {

+ 8 - 0
Filter/FilterInterface.php

@@ -71,4 +71,12 @@ interface FilterInterface
      * @return void
      */
     function getFieldType();
+
+    /**
+     * Returns the main widget used to render the filter
+     *
+     * @abstract
+     * @return void
+     */
+    function getRenderSettings();
 }

+ 22 - 9
Filter/ORM/BooleanFilter.php

@@ -11,7 +11,7 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Sonata\AdminBundle\Form\Type\Filter\BooleanType;
+use Sonata\AdminBundle\Form\Type\BooleanType;
 
 class BooleanFilter extends Filter
 {
@@ -19,19 +19,23 @@ class BooleanFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param mixed $value
+     * @param mixed $data
      * @return
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
-        if (is_array($value)) {
+        if (!$data || !is_array($data) || !array_key_exists('type', $data) || !array_key_exists('value', $data)) {
+            return;
+        }
+
+        if (is_array($data['value'])) {
             $values = array();
-            foreach ($value as $v) {
+            foreach ($data['value'] as $v) {
                 if (!in_array($v, array(BooleanType::TYPE_NO, BooleanType::TYPE_YES))) {
                    continue;
                 }
 
-                $values[] = $v ==  ($value == BooleanType::TYPE_YES) ? 1 : 0;
+                $values[] = ($v == BooleanType::TYPE_YES) ? 1 : 0;
             }
 
             if (count($values) == 0) {
@@ -39,15 +43,24 @@ class BooleanFilter extends Filter
             }
 
             $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s', $alias, $field), $values));
-
         } else {
 
-            if (!in_array($value, array(BooleanType::TYPE_NO, BooleanType::TYPE_YES))) {
+            if (!in_array($data['value'], array(BooleanType::TYPE_NO, BooleanType::TYPE_YES))) {
                 return;
             }
 
             $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $field, $this->getName()));
-            $queryBuilder->setParameter($this->getName(), ($value == BooleanType::TYPE_YES) ? 1 : 0);
+            $queryBuilder->setParameter($this->getName(), ($data['value'] == BooleanType::TYPE_YES) ? 1 : 0);
         }
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_default', array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+            'operator_type' => 'hidden',
+            'operator_options' => array(),
+        ));
+    }
 }

+ 17 - 5
Filter/ORM/CallbackFilter.php

@@ -15,10 +15,10 @@ class CallbackFilter extends Filter
 {
     /**
      * @param QueryBuilder $queryBuilder
-     * @param mixed $value
+     * @param mixed $data
      * @return array
      */
-    protected function association($queryBuilder, $value)
+    protected function association($queryBuilder, $data)
     {
         return array($queryBuilder->getRootAlias(), false);
     }
@@ -28,16 +28,16 @@ class CallbackFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param string $value
+     * @param string $data
      * @return void
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
         if (!is_callable($this->getOption('callback'))) {
             throw new \RuntimeException(sprintf('Please provide a valid callback option "filter" for field "%s"', $this->getName()));
         }
 
-        call_user_func($this->getOption('callback'), $queryBuilder, $alias, $field, $value);
+        call_user_func($this->getOption('callback'), $queryBuilder, $alias, $field, $data);
     }
 
     /**
@@ -48,6 +48,18 @@ class CallbackFilter extends Filter
         return array(
             'callback'    => null,
             'field_type'  => 'text',
+            'operator_type' => 'hidden',
+            'operator_options' => array()
         );
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_default', array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+            'operator_type' => $this->getOption('operator_type'),
+            'operator_options' => $this->getOption('operator_options'),
+        ));
+    }
 }

+ 42 - 8
Filter/ORM/ChoiceFilter.php

@@ -12,6 +12,7 @@
 namespace Sonata\AdminBundle\Filter\ORM;
 
 use Doctrine\ORM\QueryBuilder;
+use Sonata\AdminBundle\Form\Type\Filter\ChoiceType;
 
 class ChoiceFilter extends Filter
 {
@@ -19,29 +20,62 @@ class ChoiceFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param mixed $value
+     * @param mixed $data
      * @return
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
-        if (is_array($value)) {
-            if (count($value) == 0) {
+        if (!$data || !is_array($data) || !array_key_exists('type', $data) || !array_key_exists('value', $data)) {
+            return;
+        }
+
+        if (is_array($data['value'])) {
+            if (count($data['value']) == 0) {
                 return;
             }
 
-            if (in_array('all', $value)) {
+            if (in_array('all', $data['value'])) {
                 return;
             }
 
-            $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s', $alias, $field ), $value));
+            if ($data['type'] == ChoiceType::TYPE_NOT_CONTAINS) {
+                $queryBuilder->andWhere($queryBuilder->expr()->notIn(sprintf('%s.%s', $alias, $field ), $data['value']));
+            } else {
+                $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s', $alias, $field ), $data['value']));
+            }
+
         } else {
 
-            if (empty($value) || $value == 'all') {
+            if (empty($data['value']) || $data['value'] == 'all') {
                 return;
             }
 
             $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $field, $this->getName()));
-            $queryBuilder->setParameter($this->getName(), $value);
+            $queryBuilder->setParameter($this->getName(), $data['value']);
         }
     }
+
+    /**
+     * @param $type
+     * @return bool
+     */
+    private function getOperator($type)
+    {
+        $choices = array(
+            ChoiceType::TYPE_CONTAINS         => 'IN',
+            ChoiceType::TYPE_NOT_CONTAINS     => 'NOT IN',
+            ChoiceType::TYPE_EQUAL            => '=',
+        );
+
+        return isset($choices[$type]) ? $choices[$type] : false;
+    }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_default', array(
+            'operator_type' => 'sonata_type_boolean',
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+        ));
+    }
 }

+ 50 - 13
Filter/ORM/ModelFilter.php

@@ -12,6 +12,7 @@
 namespace Sonata\AdminBundle\Filter\ORM;
 
 use Doctrine\ORM\Mapping\ClassMetadataInfo;
+use Sonata\AdminBundle\Form\Type\BooleanType;
 
 class ModelFilter extends Filter
 {
@@ -19,29 +20,51 @@ class ModelFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param mixed $value
+     * @param mixed $data
      * @return
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
-        if (is_array($value)) {
-            if (count($value) == 0) {
-                return;
-            }
+        if (!$data || !is_array($data) || !array_key_exists('type', $data) || !array_key_exists('value', $data)) {
+            return;
+        }
 
-            $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s', $alias, $field ), $value));
+        if (is_array($data['value'])) {
+            $this->handleMultiple($queryBuilder, $alias, $field, $data);
         } else {
+            $this->handleScalar($queryBuilder, $alias, $field, $data);
+        }
+    }
 
-            if (empty($value)) {
-                return;
-            }
+    protected function handleMultiple($queryBuilder, $alias, $field, $data)
+    {
+        if (count($data['value']) == 0) {
+            return;
+        }
+
+        if ($data['type'] == BooleanType::TYPE_NO) {
+            $queryBuilder->andWhere($queryBuilder->expr()->notIn(sprintf('%s.%s', $alias, $field), $data['value']));
+        } else {
+            $queryBuilder->andWhere($queryBuilder->expr()->in(sprintf('%s.%s', $alias, $field), $data['value']));
+        }
+    }
 
+    protected function handleScalar($queryBuilder, $alias, $field, $data)
+    {
+        if (empty($data['value'])) {
+            return;
+        }
+
+        if ($data['type'] == BooleanType::TYPE_NO) {
+            $queryBuilder->andWhere(sprintf('%s.%s != :%s', $alias, $field, $this->getName()));
+        } else {
             $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $field, $this->getName()));
-            $queryBuilder->setParameter($this->getName(), $value);
         }
+
+        $queryBuilder->setParameter($this->getName(), $data['value']);
     }
 
-    protected function association($queryBuilder, $value)
+    protected function association($queryBuilder, $data)
     {
         $types = array(
             ClassMetadataInfo::ONE_TO_ONE,
@@ -67,7 +90,21 @@ class ModelFilter extends Filter
     {
         return array(
             'mapping_type' => false,
-            'field_name' => false
+            'field_name'   => false,
+            'field_type'   => 'entity',
+            'field_options' => array(),
+            'operator_type' => 'sonata_type_boolean',
+            'operator_options' => array(),
         );
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_default', array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+            'operator_type' => $this->getOption('operator_type'),
+            'operator_options' => $this->getOption('operator_options'),
+        ));
+    }
 }

+ 13 - 5
Filter/ORM/NumberFilter.php

@@ -19,16 +19,16 @@ class NumberFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param string $value
+     * @param string $data
      * @return
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
-        if ($value == null || !is_array($value)) {
+        if (!$data || !is_array($data) || !array_key_exists('type', $data) || !array_key_exists('value', $data)) {
             return;
         }
 
-        $operator = $this->getOperator((int) $value['type']);
+        $operator = $this->getOperator((int) $data['type']);
 
         if (!$operator) {
             return;
@@ -36,7 +36,7 @@ class NumberFilter extends Filter
 
         // c.name > '1' => c.name OPERATOR :FIELDNAME
         $queryBuilder->andWhere(sprintf('%s.%s %s :%s', $alias, $field, $operator, $this->getName()));
-        $queryBuilder->setParameter($this->getName(),  $value['value']);
+        $queryBuilder->setParameter($this->getName(),  $data['value']);
     }
 
     /**
@@ -55,4 +55,12 @@ class NumberFilter extends Filter
 
         return isset($choices[$type]) ? $choices[$type] : false;
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_number', array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+        ));
+    }
 }

+ 19 - 9
Filter/ORM/StringFilter.php

@@ -19,22 +19,24 @@ class StringFilter extends Filter
      * @param QueryBuilder $queryBuilder
      * @param string $alias
      * @param string $field
-     * @param string $value
+     * @param string $data
      * @return
      */
-    public function filter($queryBuilder, $alias, $field, $value)
+    public function filter($queryBuilder, $alias, $field, $data)
     {
-        if (!is_array($value)) {
+        if (!$data || !is_array($data) || !array_key_exists('value', $data)) {
             return;
         }
 
-        $value['text'] = trim($value['text']);
+        $data['value'] = trim($data['value']);
 
-        if (strlen($value['text']) == 0) {
+        if (strlen($data['value']) == 0) {
             return;
         }
 
-        $operator = $this->getOperator((int) $value['type']);
+        $data['type'] = !isset($data['type']) ?  ChoiceType::TYPE_CONTAINS : $data['type'];
+
+        $operator = $this->getOperator((int) $data['type']);
 
         if (!$operator) {
             $operator = 'LIKE';
@@ -43,10 +45,10 @@ class StringFilter extends Filter
         // c.name > '1' => c.name OPERATOR :FIELDNAME
         $queryBuilder->andWhere(sprintf('%s.%s %s :%s', $alias, $field, $operator, $this->getName()));
 
-        if ($value['type'] == ChoiceType::TYPE_EQUAL) {
-            $queryBuilder->setParameter($this->getName(), $value['text']);
+        if ($data['type'] == ChoiceType::TYPE_EQUAL) {
+            $queryBuilder->setParameter($this->getName(), $data['value']);
         } else {
-            $queryBuilder->setParameter($this->getName(), sprintf($this->getOption('format'), $value['text']));
+            $queryBuilder->setParameter($this->getName(), sprintf($this->getOption('format'), $data['value']));
         }
     }
 
@@ -74,4 +76,12 @@ class StringFilter extends Filter
             'format'   => '%%%s%%'
         );
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_choice', array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+        ));
+    }
 }

+ 1 - 1
Form/Type/Filter/BooleanType.php

@@ -9,7 +9,7 @@
  *
  */
 
-namespace Sonata\AdminBundle\Form\Type\Filter;
+namespace Sonata\AdminBundle\Form\Type;
 
 use Symfony\Component\Form\Extension\Core\Type\ChoiceType as FormChoiceType;
 use Symfony\Component\Translation\TranslatorInterface;

+ 13 - 1
Form/Type/Filter/ChoiceType.php

@@ -53,7 +53,19 @@ class ChoiceType extends AbstractType
 
         $builder
             ->add('type', 'choice', array('choices' => $choices, 'required' => false))
-            ->add('text', 'text', array('required' => false))
+            ->add('value', $options['field_type'], array_merge(array('required' => false), $options['field_options']))
         ;
     }
+
+    public function getDefaultOptions(array $options)
+    {
+        $defaultOptions = array(
+            'field_type'       => 'choice',
+            'field_options'    => array()
+        );
+
+        $options = array_replace($options, $defaultOptions);
+
+        return $options;
+    }
 }

+ 54 - 0
Form/Type/Filter/DefaultType.php

@@ -0,0 +1,54 @@
+<?php
+/*
+ * This file is part of the Sonata package.
+ *
+ * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ */
+
+namespace Sonata\AdminBundle\Form\Type\Filter;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormTypeInterface;
+use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\FormInterface;
+use Symfony\Component\Translation\TranslatorInterface;
+
+class DefaultType extends AbstractType
+{
+    /**
+     * Returns the name of this type.
+     *
+     * @return string The name of this type
+     */
+    function getName()
+    {
+        return 'sonata_type_filter_default';
+    }
+
+    public function buildForm(FormBuilder $builder, array $options)
+    {
+        $builder
+            ->add('type', $options['operator_type'], array_merge(array('required' => false), $options['operator_options']))
+            ->add('value', $options['field_type'], array_merge(array('required' => false), $options['field_options']))
+        ;
+    }
+
+    public function getDefaultOptions(array $options)
+    {
+        $defaultOptions = array(
+            'operator_type'    => 'hidden',
+            'operator_options' => array(),
+            'field_type'       => 'text',
+            'field_options'    => array()
+        );
+
+        $options = array_replace($options, $defaultOptions);
+
+        return $options;
+    }
+}

+ 6 - 3
Guesser/ORM/FilterTypeGuesser.php

@@ -59,6 +59,9 @@ class FilterTypeGuesser implements TypeGuesserInterface
                 case ClassMetadataInfo::MANY_TO_ONE:
                 case ClassMetadataInfo::MANY_TO_MANY:
 
+                    $options['operator_type'] = 'sonata_type_boolean';
+                    $options['operator_options'] = array();
+
                     $options['field_type'] = 'entity';
                     $options['field_options'] = array(
                         'class' => $mapping['targetEntity']
@@ -74,7 +77,7 @@ class FilterTypeGuesser implements TypeGuesserInterface
 
         switch ($metadata->getTypeOfField($property)) {
             case 'boolean':
-                $options['field_type'] = 'sonata_type_filter_boolean';
+                $options['field_type'] = 'sonata_type_boolean';
                 $options['field_options'] = array();
 
                 return new TypeGuess('doctrine_orm_boolean', $options, Guess::HIGH_CONFIDENCE);
@@ -90,7 +93,7 @@ class FilterTypeGuesser implements TypeGuesserInterface
             case 'integer':
             case 'bigint':
             case 'smallint':
-                $options['field_type'] = 'sonata_type_filter_number';
+                $options['field_type'] = 'number';
                 $options['field_options'] = array(
                     'csrf_protection' => false
                 );
@@ -98,7 +101,7 @@ class FilterTypeGuesser implements TypeGuesserInterface
                 return new TypeGuess('doctrine_orm_number', $options, Guess::MEDIUM_CONFIDENCE);
             case 'string':
             case 'text':
-                $options['field_type'] = 'sonata_type_filter_choice';
+                $options['field_type'] = 'text';
 
                 return new TypeGuess('doctrine_orm_string', $options, Guess::MEDIUM_CONFIDENCE);
             case 'time':

+ 0 - 4
Resources/config/doctrine_orm_filter_types.xml

@@ -21,10 +21,6 @@
             <tag name="sonata.admin.filter.type" alias="doctrine_orm_model" />
         </service>
 
-        <service id="sonata.admin.orm.filter.type.integer" class="Sonata\AdminBundle\Filter\ORM\IntegerFilter">
-            <tag name="sonata.admin.filter.type" alias="doctrine_orm_integer" />
-        </service>
-
         <service id="sonata.admin.orm.filter.type.string" class="Sonata\AdminBundle\Filter\ORM\StringFilter">
             <tag name="sonata.admin.filter.type" alias="doctrine_orm_string" />
         </service>

+ 8 - 6
Resources/config/form_types.xml

@@ -27,6 +27,12 @@
             <tag name="form.type" alias="sonata_type_immutable_array" />
         </service>
 
+        <service id="sonata.admin.form.type.boolean" class="Sonata\AdminBundle\Form\Type\BooleanType">
+            <tag name="form.type" alias="sonata_type_boolean" />
+
+            <argument type="service" id="translator" />
+        </service>
+
         <!-- Form Extension -->
         <service id="sonata.admin.form.extension.field" class="Sonata\AdminBundle\Form\Extension\Field\Type\FormTypeFieldExtension">
             <tag name="form.type_extension" alias="field" />
@@ -45,13 +51,9 @@
             <argument type="service" id="translator" />
         </service>
 
-
-        <service id="sonata.admin.form.filter.type.boolean" class="Sonata\AdminBundle\Form\Type\Filter\BooleanType">
-            <tag name="form.type" alias="sonata_type_filter_boolean" />
-
-            <argument type="service" id="translator" />
+        <service id="sonata.admin.form.filter.type.default" class="Sonata\AdminBundle\Form\Type\Filter\DefaultType">
+            <tag name="form.type" alias="sonata_type_filter_default" />
         </service>
-
     </services>
 
 </container>

+ 46 - 31
Resources/doc/reference/filter_field_definition.rst

@@ -4,6 +4,37 @@ Filter Field Definition
 These fields are displayed inside the filter box. They allow you to filter
 the list of entities by a number of different methods.
 
+A filter instance is always linked to a Form Type, there is 3 types availables :
+
+  - sonata_type_filter_number  :  display 2 widgets, the operator ( >, >=, <= , <, =) and the value
+  - sonata_type_filter_choice  :  display 2 widgets, the operator (yes and no) and the value
+  - sonata_type_filter_default :  display 2 widgets, an hidden operator (can be changed on demand) and the value
+  - sonata_type_filter_date ( not implemented yet )
+
+The Form Type configuration is provided by the filter itself. But they can be tweaked in the ``configureDatagridFilters``
+process with the ``add`` method.
+
+The ``add`` method accepts 4 arguments :
+
+  - the field name
+  - the filter type     : the filter name
+  - the filter options  : the options related to the filter
+  - the field type      : the type of widget used to render the value part
+  - the field options   : the type options
+
+Type available
+---------------
+
+For now, only Doctrine ORM filters are available
+
+  - doctrine_orm_boolean   : depends on the ``sonata_type_filter_default`` Form Type, render yes or no field
+  - doctrine_orm_callback  : depends on the ``sonata_type_filter_default`` Form Type, types can be configured as needed
+  - doctrine_orm_choice    : depends on the ``sonata_type_filter_choice`` Form Type, render yes or no field
+  - doctrine_orm_model     : depends on the ``sonata_type_filter_number`` Form Type
+  - doctrine_orm_string    : depends on the ``sonata_type_filter_choice``
+  - doctrine_orm_number    : depends on the ``sonata_type_filter_choice`` Form Type, render yes or no field
+
+
 Example
 -------
 
@@ -26,31 +57,11 @@ Example
             $datagrid
                 ->add('title');
                 ->add('enabled');
-                ->add('tags', null, array('filter_field_options' => array('expanded' => true, 'multiple' => true))
+                ->add('tags', null, array(), null, array('expanded' => true, 'multiple' => true)
             ;
         }
     }
 
-Types available
----------------
-
-- checkbox
-- callback
-- decimal
-- identifier
-- integer
-- text
-
-If no type is set, the Admin class will use the one set in the Doctrine mapping
-definition.
-
-Tweak it!
----------
-
-- It is possible to change the default template by setting a ``template`` key
-  in the options array.
-- If the project requires specific behaviors, they can be implemented in the
-  ``configureFilterFields()`` method.
 
 Advanced usage
 --------------
@@ -81,16 +92,20 @@ this functionality.
             $datagridMapper
                 ->add('title')
                 ->add('enabled')
-                ->add('tags', 'orm_many_to_many', array('filter_field_options' => array('expanded' => true, 'multiple' => true)))
-                ->add('with_open_comments', 'callback', array(
-                    'template' => 'SonataAdminBundle:CRUD:filter_callback.html.twig',
-                    'filter_options' => array(
-                        'filter' => array($this, 'getWithOpenCommentFilter'),
-                        'type'   => 'checkbox'
-                    ),
-                    'filter_field_options' => array(
-                        'required' => false
-                    )
+                ->add('tags', null, array(), null, array('expanded' => true, 'multiple' => true))
+                ->add('author')
+                ->add('with_open_comments', 'doctrine_orm_callback', array(
+    //                'callback'   => array($this, 'getWithOpenCommentFilter'),
+                    'callback' => function($queryBuilder, $alias, $field, $value) {
+                        if (!$value) {
+                            return;
+                        }
+
+                        $queryBuilder->leftJoin(sprintf('%s.comments', $alias), 'c');
+                        $queryBuilder->andWhere('c.status = :status');
+                        $queryBuilder->setParameter('status', Comment::STATUS_MODERATE);
+                    },
+                    'field_type' => 'checkbox'
                 ))
             ;
         }

+ 0 - 2
Tests/Filter/FilterFactoryTest.php

@@ -15,7 +15,6 @@ use Sonata\AdminBundle\Filter\FilterFactory;
 
 class FilterFactoryTest extends \PHPUnit_Framework_TestCase
 {
-
     /**
      * @expectedException RuntimeException
      */
@@ -38,7 +37,6 @@ class FilterFactoryTest extends \PHPUnit_Framework_TestCase
         $filter->create('test', 'mytype');
     }
 
-
     /**
      * @expectedException RuntimeException
      */

+ 4 - 4
Tests/Filter/ORM/BooleanFilterTest.php

@@ -12,7 +12,7 @@
 namespace Sonata\AdminBundle\Tests\Filter\ORM;
 
 use Sonata\AdminBundle\Filter\ORM\BooleanFilter;
-use Sonata\AdminBundle\Form\Type\Filter\BooleanType;
+use Sonata\AdminBundle\Form\Type\BooleanType;
 
 class BooleanFilterTest extends \PHPUnit_Framework_TestCase
 {
@@ -41,7 +41,7 @@ class BooleanFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', BooleanType::TYPE_NO);
+        $filter->filter($builder, 'alias', 'field', array('type' => null, 'value' => BooleanType::TYPE_NO));
 
         $this->assertEquals(array('alias.field = :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 0), $builder->parameters);
@@ -54,7 +54,7 @@ class BooleanFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', BooleanType::TYPE_YES);
+        $filter->filter($builder, 'alias', 'field', array('type' => null, 'value' => BooleanType::TYPE_YES));
 
         $this->assertEquals(array('alias.field = :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 1), $builder->parameters);
@@ -67,7 +67,7 @@ class BooleanFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', array(BooleanType::TYPE_NO));
+        $filter->filter($builder, 'alias', 'field', array('type' => null, 'value' => array(BooleanType::TYPE_NO)));
 
         $this->assertEquals(array('in_alias.field', 'alias.field IN ("0")'), $builder->query);
     }

+ 3 - 2
Tests/Filter/ORM/ChoiceFilterTest.php

@@ -12,6 +12,7 @@
 namespace Sonata\AdminBundle\Tests\Filter\ORM;
 
 use Sonata\AdminBundle\Filter\ORM\ChoiceFilter;
+use Sonata\AdminBundle\Form\Type\Filter\ChoiceType;
 
 class ChoiceFilterTest extends \PHPUnit_Framework_TestCase
 {
@@ -36,7 +37,7 @@ class ChoiceFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', array('1', '2'));
+        $filter->filter($builder, 'alias', 'field', array('type' => ChoiceType::TYPE_CONTAINS, 'value' => array('1', '2')));
 
         $this->assertEquals(array('in_alias.field', 'alias.field IN ("1,2")'), $builder->query);
     }
@@ -48,7 +49,7 @@ class ChoiceFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', '1');
+        $filter->filter($builder, 'alias', 'field', array('type' => ChoiceType::TYPE_CONTAINS, 'value' => '1'));
 
         $this->assertEquals(array('alias.field = :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => '1'), $builder->parameters);

+ 8 - 0
Tests/Filter/ORM/FilterTest.php

@@ -33,6 +33,14 @@ class FilterTest_Filter extends Filter
     {
         return array('option1' => 2);
     }
+
+    public function getRenderSettings()
+    {
+        return array('sonata_type_filter_default', array(
+            'type'    => $this->getFieldType(),
+            'options' => $this->getFieldOptions()
+        ));
+    }
 }
 
 

+ 4 - 3
Tests/Filter/ORM/ModelFilterTest.php

@@ -13,6 +13,7 @@ namespace Sonata\AdminBundle\Tests\Filter\ORM;
 
 use Sonata\AdminBundle\Filter\ORM\ModelFilter;
 use Doctrine\ORM\Mapping\ClassMetadataInfo;
+use Sonata\AdminBundle\Form\Type\Filter\ChoiceType;
 
 class ModelFilterTest extends \PHPUnit_Framework_TestCase
 {
@@ -50,7 +51,7 @@ class ModelFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', array('1', '2'));
+        $filter->filter($builder, 'alias', 'field', array('type' => ChoiceType::TYPE_CONTAINS, 'value' => array('1', '2')));
 
         $this->assertEquals(array('in_alias.field', 'alias.field IN ("1,2")'), $builder->query);
     }
@@ -62,7 +63,7 @@ class ModelFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->filter($builder, 'alias', 'field', 2);
+        $filter->filter($builder, 'alias', 'field', array('type' => ChoiceType::TYPE_CONTAINS, 'value' => 2));
 
         $this->assertEquals(array('alias.field = :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 2), $builder->parameters);
@@ -100,7 +101,7 @@ class ModelFilterTest extends \PHPUnit_Framework_TestCase
 
         $builder = new QueryBuilder;
 
-        $filter->apply($builder, 'asd');
+        $filter->apply($builder, array('type' => ChoiceType::TYPE_CONTAINS, 'value' => 'asd'));
 
         $this->assertEquals(array('o.field_name', 'field_name.id = :field_name'), $builder->query);
     }

+ 4 - 4
Tests/Filter/ORM/StringFilterTest.php

@@ -37,7 +37,7 @@ class StringFilterTest extends \PHPUnit_Framework_TestCase
         $builder = new QueryBuilder;
         $this->assertEquals(array(), $builder->query);
 
-        $filter->filter($builder, 'alias', 'field', array('text' => 'asd', 'type' => ChoiceType::TYPE_CONTAINS));
+        $filter->filter($builder, 'alias', 'field', array('value' => 'asd', 'type' => ChoiceType::TYPE_CONTAINS));
         $this->assertEquals(array('alias.field LIKE :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 'asd'), $builder->parameters);
 
@@ -45,7 +45,7 @@ class StringFilterTest extends \PHPUnit_Framework_TestCase
         $builder = new QueryBuilder;
         $this->assertEquals(array(), $builder->query);
 
-        $filter->filter($builder, 'alias', 'field', array('text' => 'asd', 'type' => null));
+        $filter->filter($builder, 'alias', 'field', array('value' => 'asd', 'type' => null));
         $this->assertEquals(array('alias.field LIKE :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 'asd'), $builder->parameters);
     }
@@ -58,7 +58,7 @@ class StringFilterTest extends \PHPUnit_Framework_TestCase
         $builder = new QueryBuilder;
         $this->assertEquals(array(), $builder->query);
 
-        $filter->filter($builder, 'alias', 'field', array('text' => 'asd', 'type' => ChoiceType::TYPE_NOT_CONTAINS));
+        $filter->filter($builder, 'alias', 'field', array('value' => 'asd', 'type' => ChoiceType::TYPE_NOT_CONTAINS));
         $this->assertEquals(array('alias.field NOT LIKE :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 'asd'), $builder->parameters);
     }
@@ -71,7 +71,7 @@ class StringFilterTest extends \PHPUnit_Framework_TestCase
         $builder = new QueryBuilder;
         $this->assertEquals(array(), $builder->query);
 
-        $filter->filter($builder, 'alias', 'field', array('text' => 'asd', 'type' => ChoiceType::TYPE_EQUAL));
+        $filter->filter($builder, 'alias', 'field', array('value' => 'asd', 'type' => ChoiceType::TYPE_EQUAL));
         $this->assertEquals(array('alias.field = :field_name'), $builder->query);
         $this->assertEquals(array('field_name' => 'asd'), $builder->parameters);
     }