Browse Source

Add NumberFilter, Fix Choice filter

Thomas Rabaix 14 năm trước cách đây
mục cha
commit
6a07de0fe7

+ 12 - 8
Builder/ORM/DatagridBuilder.php

@@ -125,14 +125,24 @@ class DatagridBuilder implements DatagridBuilderInterface
         if ($type == null) {
             $guessType = $this->guesser->guessType($admin->getClass(), $fieldDescription->getName());
             $fieldDescription->setType($guessType->getType());
+            $options = $guessType->getOptions();
+
+            $fieldDescription->setOption('options', $options['options']);
+            $fieldDescription->setOption('field_options', $options['field_options']);
+            $fieldDescription->setOption('field_type',    $options['field_type']);
         } else {
             $fieldDescription->setType($type);
+            $options = array(
+                'options' => $fieldDescription->getOption('options', array()),
+                'field_options' => $fieldDescription->getOption('field_options', array()),
+                'field_type'    => $fieldDescription->getOption('field_type', array())
+            );
         }
 
         $this->fixFieldDescription($admin, $fieldDescription);
         $admin->addFilterFieldDescription($fieldDescription->getName(), $fieldDescription);
 
-        $filter = $this->filterFactory->create($fieldDescription);
+        $filter = $this->filterFactory->create($fieldDescription, $options);
 
         $datagrid->addFilter($filter);
 
@@ -152,12 +162,6 @@ class DatagridBuilder implements DatagridBuilderInterface
         $pager = new Pager;
         $pager->setCountColumn($admin->getModelManager()->getIdentifierFieldNames($admin->getClass()));
 
-        return new Datagrid(
-            $query,
-            $admin->getList(),
-            $pager,
-            $this->formFactory,
-            $values
-        );
+        return new Datagrid($query, $admin->getList(), $pager, $values);
     }
 }

+ 1 - 4
Datagrid/Datagrid.php

@@ -41,13 +41,12 @@ class Datagrid implements DatagridInterface
 
     protected $results;
 
-    public function __construct(ProxyQueryInterface $query, FieldDescriptionCollection $columns, PagerInterface $pager, FormFactory $formFactory, array $values = array())
+    public function __construct(ProxyQueryInterface $query, FieldDescriptionCollection $columns, PagerInterface $pager, array $values = array())
     {
         $this->pager    = $pager;
         $this->query    = $query;
         $this->values   = $values;
         $this->columns  = $columns;
-        $this->formFactory = $formFactory;
     }
 
     /**
@@ -98,8 +97,6 @@ class Datagrid implements DatagridInterface
      */
     public function addFilter(FilterInterface $filter)
     {
-        $filter->defineFieldBuilder($this->formFactory);
-
         $this->filters[$filter->getName()] = $filter;
     }
 

+ 28 - 0
Filter/Filter.php

@@ -14,6 +14,7 @@ namespace Sonata\AdminBundle\Filter;
 use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
 use Sonata\AdminBundle\Filter\FilterInterface;
 use Doctrine\ORM\QueryBuilder;
+use Symfony\Component\Form\FormFactory;
 
 abstract class Filter implements FilterInterface
 {
@@ -73,4 +74,31 @@ abstract class Filter implements FilterInterface
 
         return $default;
     }
+
+    /**
+     * @param \Symfony\Component\Form\FormFactory $formFactory
+     * @return void
+     */
+    public function defineFieldBuilder(FormFactory $formFactory)
+    {
+        $builder = $formFactory->createNamedBuilder($this->getFieldType(), $this->getName(), null, $this->getFieldOptions());
+
+        $this->field = $builder->getForm();
+    }
+
+    /**
+     * @return string
+     */
+    public function getFieldType()
+    {
+        return $this->getOption('field_type', 'text');
+    }
+
+    /**
+     * @return array
+     */
+    public function getFieldOptions()
+    {
+        return $this->getOption('field_options', array('required' => false));
+    }
 }

+ 13 - 8
Filter/FilterFactory.php

@@ -37,15 +37,15 @@ class FilterFactory implements FilterFactoryInterface
 
     /**
      * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
-     * @param array $options
      * @return void
      */
-    public function create($type, array $options = array())
+    public function create(FieldDescriptionInterface $fieldDescription, array $options = array())
     {
-        if (!is_string($type)) {
-            throw new \RunTimeException('Type must be a string');
+        if (!$fieldDescription->getType()) {
+            throw new \RunTimeException('The type must be defined');
         }
 
+        $type = $fieldDescription->getType();
 //        $
 //        switch($fieldDescription->getMappingType()) {
 //            case ClassMetadataInfo::MANY_TO_ONE:
@@ -76,14 +76,19 @@ class FilterFactory implements FilterFactoryInterface
             throw new \RunTimeException(sprintf('No attached service to type named `%s`', $type));
         }
 
-        $type = $this->container->get($id);
+        $filter = $this->container->get($id);
 
-        if (!$type instanceof FilterInterface) {
+        if (!$filter instanceof FilterInterface) {
             throw new \RunTimeException(sprintf('The service `%s` must implement `FilterInterface`', $id));
         }
 
-        $type->initialize($options);
+        $filter->setFieldDescription($fieldDescription);
+        $options['field_options']['csrf_protection'] = false;
+        $options['field_options']['required'] = false;
 
-        return $type;
+        $filter->initialize($options);
+        $filter->defineFieldBuilder($this->container->get('form.factory'));
+
+        return $filter;
     }
 }

+ 1 - 1
Filter/FilterFactoryInterface.php

@@ -16,5 +16,5 @@ use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
 
 interface FilterFactoryInterface
 {
-    public function create(FieldDescriptionInterface $fieldDescription);
+    public function create(FieldDescriptionInterface $fieldDescription, array $options = array());
 }

+ 1 - 18
Filter/ORM/ChoiceFilter.php

@@ -11,7 +11,6 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Symfony\Component\Form\FormFactory;
 use Doctrine\ORM\QueryBuilder;
 
 class ChoiceFilter extends Filter
@@ -44,25 +43,9 @@ class ChoiceFilter extends Filter
                 return;
             }
 
-            $queryBuilder->andWhere(sprintf('%s.%s = :%s',
-                $alias,
-                $field,
-                $this->getName()
-            ));
+            $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $field, $this->getName()));
 
             $queryBuilder->setParameter($this->getName(), $value);
         }
     }
-
-    /**
-     * @param \Symfony\Component\Form\FormFactory $formFactory
-     * @param null $value
-     * @return void
-     */
-    public function defineFieldBuilder(FormFactory $formFactory, $value = null)
-    {
-        $options = $this->getFieldDescription()->getOption('filter_field_options', array('required' => false));
-
-        $this->field = $formFactory->createNamedBuilder('choice', $this->getName(), $value, $options)->getForm();
-    }
 }

+ 0 - 64
Filter/ORM/IntegerFilter.php

@@ -1,64 +0,0 @@
-<?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\Filter\ORM;
-
-use Doctrine\ORM\QueryBuilder;
-use Symfony\Component\Form\FormFactory;
-
-class IntegerFilter extends Filter
-{
-    /**
-     * @param QueryBuilder $queryBuilder
-     * @param string $alias
-     * @param string $field
-     * @param string $value
-     * @return
-     */
-    public function filter($queryBuilder, $alias, $field, $value)
-    {
-        if ($value == null) {
-            return;
-        }
-
-        // c.name > '1' => c.name OPERATOR :FIELDNAME
-        $queryBuilder->andWhere(sprintf('%s.%s %s :%s',
-            $alias,
-            $field,
-            $this->getOption('operator'),
-            $this->getName()
-        ));
-
-        $queryBuilder->setParameter($this->getName(), (int)sprintf($this->getOption('format'), $value));
-    }
-
-    /**
-     * @return array
-     */
-    public function getDefaultOptions()
-    {
-        return array(
-            'operator' => '=',
-            'format'   => '%d'
-        );
-    }
-
-    /**
-     * @param \Symfony\Component\Form\FormFactory $formFactory
-     * @return void
-     */
-    public function defineFieldBuilder(FormFactory $formFactory)
-    {
-        $options = $this->fieldDescription->getOption('filter_field_options', array('required' => false));
-
-        $this->field = $formFactory->createNamedBuilder('text', $this->getName(), null, $options)->getForm();
-    }
-}

+ 58 - 0
Filter/ORM/NumberFilter.php

@@ -0,0 +1,58 @@
+<?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\Filter\ORM;
+
+use Sonata\AdminBundle\Form\Type\Filter\NumberType;
+
+class NumberFilter extends Filter
+{
+    /**
+     * @param QueryBuilder $queryBuilder
+     * @param string $alias
+     * @param string $field
+     * @param string $value
+     * @return
+     */
+    public function filter($queryBuilder, $alias, $field, $value)
+    {
+        if ($value == null) {
+            return;
+        }
+
+        $operator = $this->getOperator((int) $value['type']);
+
+        if (!$operator) {
+            return;
+        }
+
+        // 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']);
+    }
+
+    /**
+     * @param $type
+     * @return bool
+     */
+    private function getOperator($type)
+    {
+         $choices = array(
+            NumberType::TYPE_EQUAL            => '=',
+            NumberType::TYPE_GREATER_EQUAL    => '>=',
+            NumberType::TYPE_GREATER_THAN     => '>',
+            NumberType::TYPE_LESS_EQUAL       => '<=',
+            NumberType::TYPE_LESS_THAN        => '<',
+        );
+
+        return isset($choices[$type]) ? $choices[$type] : false;
+    }
+}

+ 0 - 15
Filter/ORM/StringFilter.php

@@ -11,12 +11,8 @@
 
 namespace Sonata\AdminBundle\Filter\ORM;
 
-use Symfony\Component\Form\FormFactory;
-use Doctrine\ORM\QueryBuilder;
-
 class StringFilter extends Filter
 {
-
     /**
      * @param Querybuilder $queryBuilder
      * @param string $alias
@@ -51,15 +47,4 @@ class StringFilter extends Filter
             'format'   => '%%%s%%'
         );
     }
-
-    /**
-     * @param \Symfony\Component\Form\FormFactory $formFactory
-     * @return void
-     */
-    public function defineFieldBuilder(FormFactory $formFactory)
-    {
-        $options = $this->fieldDescription->getOption('filter_field_options', array('required' => false));
-
-        $this->field = $formFactory->createNamedBuilder('text', $this->getName(), null, $options)->getForm();
-    }
 }

+ 65 - 0
Form/Type/Filter/NumberType.php

@@ -0,0 +1,65 @@
+<?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 NumberType extends AbstractType
+{
+    const TYPE_GREATER_EQUAL = 1;
+
+    const TYPE_GREATER_THAN = 2;
+
+    const TYPE_EQUAL = 3;
+
+    const TYPE_LESS_EQUAL = 4;
+
+    const TYPE_LESS_THAN = 5;
+
+    protected $translator;
+
+    public function __construct(TranslatorInterface $translator)
+    {
+        $this->translator = $translator;
+    }
+
+    /**
+     * Returns the name of this type.
+     *
+     * @return string The name of this type
+     */
+    function getName()
+    {
+        return 'sonata_type_filter_number';
+    }
+
+    public function buildForm(FormBuilder $builder, array $options)
+    {
+        $choices = array(
+            self::TYPE_EQUAL            => $this->translator->trans('label_type_equal', array(), 'SonataAdminBundle'),
+            self::TYPE_GREATER_EQUAL    => $this->translator->trans('label_type_greater_equal', array(), 'SonataAdminBundle'),
+            self::TYPE_GREATER_THAN     => $this->translator->trans('label_type_greater_than', array(), 'SonataAdminBundle'),
+            self::TYPE_LESS_EQUAL       => $this->translator->trans('label_type_less_equal', array(), 'SonataAdminBundle'),
+            self::TYPE_LESS_THAN        => $this->translator->trans('label_type_less_than', array(), 'SonataAdminBundle'),
+        );
+
+        $builder
+            ->add('type', 'choice', array('choices' => $choices, 'required' => false))
+            ->add('value', 'number', array('required' => false))
+        ;
+    }
+}

+ 27 - 14
Guesser/ORM/FilterTypeGuesser.php

@@ -38,9 +38,18 @@ class FilterTypeGuesser implements TypeGuesserInterface
     function guessType($class, $property)
     {
         if (!$ret = $this->getMetadata($class)) {
-            return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
+            return false;
         }
 
+        $options = array(
+            'field_type' => false,
+            'field_options' => array(
+                'required' => false,
+                'csrf_protection' => false
+            ),
+            'options' => array(),
+        );
+
         list($metadata, $name) = $ret;
 
         if ($metadata->hasAssociation($property)) {
@@ -49,44 +58,48 @@ class FilterTypeGuesser implements TypeGuesserInterface
 
             switch ($mapping['type']) {
                 case ClassMetadataInfo::ONE_TO_MANY:
-                    return new TypeGuess('orm_one_to_many', array(), Guess::HIGH_CONFIDENCE);
+                    return new TypeGuess('orm_one_to_many', $options, Guess::HIGH_CONFIDENCE);
 
                 case ClassMetadataInfo::MANY_TO_MANY:
-                    return new TypeGuess('orm_many_to_many', array(), Guess::HIGH_CONFIDENCE);
+                    return new TypeGuess('orm_many_to_many', $options, Guess::HIGH_CONFIDENCE);
 
                 case ClassMetadataInfo::MANY_TO_ONE:
-                    return new TypeGuess('orm_many_to_one', array(), Guess::HIGH_CONFIDENCE);
+                    return new TypeGuess('orm_many_to_one', $options, Guess::HIGH_CONFIDENCE);
 
                 case ClassMetadataInfo::ONE_TO_ONE:
-                    return new TypeGuess('orm_one_to_one', array(), Guess::HIGH_CONFIDENCE);
+                    return new TypeGuess('orm_one_to_one', $options, Guess::HIGH_CONFIDENCE);
             }
         }
 
         switch ($metadata->getTypeOfField($property)) {
             //case 'array':
-            //  return new TypeGuess('Collection', array(), Guess::HIGH_CONFIDENCE);
+            //  return new TypeGuess('Collection', $options, Guess::HIGH_CONFIDENCE);
             case 'boolean':
-                return new TypeGuess('doctrine_orm_checkbox', array(), Guess::HIGH_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_checkbox', $options, Guess::HIGH_CONFIDENCE);
             case 'datetime':
             case 'vardatetime':
             case 'datetimetz':
-                return new TypeGuess('doctrine_orm_datetime', array(), Guess::HIGH_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_datetime', $options, Guess::HIGH_CONFIDENCE);
             case 'date':
-                return new TypeGuess('doctrine_orm_date', array(), Guess::HIGH_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_date', $options, Guess::HIGH_CONFIDENCE);
             case 'decimal':
             case 'float':
-                return new TypeGuess('doctrine_orm_number', array(), Guess::MEDIUM_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_number', $options, Guess::MEDIUM_CONFIDENCE);
             case 'integer':
             case 'bigint':
             case 'smallint':
-                return new TypeGuess('doctrine_orm_integer', array(), Guess::MEDIUM_CONFIDENCE);
+                $options['field_type'] = 'sonata_type_filter_number';
+
+                return new TypeGuess('doctrine_orm_number', $options, Guess::MEDIUM_CONFIDENCE);
             case 'string':
             case 'text':
-                return new TypeGuess('doctrine_orm_textarea', array(), Guess::MEDIUM_CONFIDENCE);
+                $options['field_type'] = 'text';
+
+                return new TypeGuess('doctrine_orm_string', $options, Guess::MEDIUM_CONFIDENCE);
             case 'time':
-                return new TypeGuess('doctrine_orm_time', array(), Guess::HIGH_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_time', $options, Guess::HIGH_CONFIDENCE);
             default:
-                return new TypeGuess('doctrine_orm_text', array(), Guess::LOW_CONFIDENCE);
+                return new TypeGuess('doctrine_orm_string', $options, Guess::LOW_CONFIDENCE);
         }
     }
 

+ 4 - 0
Resources/config/doctrine_orm_filter_types.xml

@@ -25,6 +25,10 @@
         <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>
+
+        <service id="sonata.admin.orm.filter.type.string" class="Sonata\AdminBundle\Filter\ORM\NumberFilter">
+            <tag name="sonata.admin.filter.type" alias="doctrine_orm_number" />
+        </service>
     </services>
 
 </container>

+ 9 - 0
Resources/config/form_types.xml

@@ -5,6 +5,8 @@
            xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
     <services>
+
+        <!-- Form Widget-->
         <service id="sonata.admin.form.type.admin" class="Sonata\AdminBundle\Form\Type\AdminType">
             <tag name="form.type" alias="sonata_type_admin" />
         </service>
@@ -25,6 +27,13 @@
             <tag name="form.type_extension" alias="field" />
         </service>
 
+        <!-- Form Filter Type -->
+        <service id="sonata.admin.form.filter.type.number" class="Sonata\AdminBundle\Form\Type\Filter\NumberType">
+            <tag name="form.type" alias="sonata_type_filter_number" />
+
+            <argument type="service" id="translator" />
+        </service>
+
     </services>
 
 </container>