Przeglądaj źródła

Add date and date range filters - Original works from @andrewtch and @somewherethere : https://github.com/sonata-project/SonataDoctrineORMAdminBundle/pull/45

Thomas Rabaix 13 lat temu
rodzic
commit
a13cf3adb5

+ 136 - 0
Filter/AbstractDateFilter.php

@@ -0,0 +1,136 @@
+<?php
+
+namespace Sonata\DoctrineORMAdminBundle\Filter;
+
+use Sonata\AdminBundle\Form\Type\Filter\DateType;
+use Sonata\AdminBundle\Form\Type\Filter\DateRangeType;
+use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
+use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
+
+abstract class AbstractDateFilter extends Filter
+{
+    /**
+     * Flag indicating that filter will have range
+     * @var boolean
+     */
+    protected $range = false;
+
+    /**
+     * Flag indicating that filter will filter by datetime instead by date
+     * @var boolean
+     */
+    protected $time = false;
+
+    /**
+     *
+     * @param \Doctrine\ORM\QueryBuilder $queryBuilder
+     * @param string $alias
+     * @param string $field
+     * @param array $data
+     * @return
+     */
+    public function filter($queryBuilder, $alias, $field, $data)
+    {
+        //check data sanity
+        if (!$data || !is_array($data) || !array_key_exists('value', $data)) {
+            return;
+        }
+
+        if ($this->range) {
+            //additional data check for ranged items
+            if (!array_key_exists('start', $data['value']) || !array_key_exists('end', $data['value'])) {
+                return;
+            }
+
+            if (!$data['value']['start'] || !$data['value']['end']) {
+                return;
+            }
+
+            //default type for range filter
+            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ?  DateRangeType::TYPE_BETWEEN : $data['type'];
+
+            if ($data['type'] == DateRangeType::TYPE_NOT_BETWEEN) {
+                $this->applyWhere($queryBuilder, sprintf('%s.%s < :%s OR %s.%s > :%s', $alias, $field, $this->getName().'_start', $alias, $field, $this->getName().'_end'));
+            } else {
+                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '>=', $this->getName().'_start'));
+                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '<=', $this->getName().'_end'));
+            }
+
+            $queryBuilder->setParameter($this->getName().'_start',  $data['value']['start']);
+            $queryBuilder->setParameter($this->getName().'_end',  $data['value']['end']);
+        } else {
+
+            if (!$data['value']) {
+                return;
+            }
+
+            //default type for simple filter
+            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ? DateType::TYPE_EQUAL : $data['type'];
+
+            //just find an operator and apply query
+            $operator = $this->getOperator($data['type']);
+
+            //null / not null only check for col
+            if (in_array($operator, array('NULL', 'NOT NULL'))) {
+                $this->applyWhere($queryBuilder, sprintf('%s.%s IS %s ', $alias, $field, $operator));
+            } else {
+                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, $operator, $this->getName()));
+                $queryBuilder->setParameter($this->getName(), $data['value']);
+            }
+        }
+    }
+
+    /**
+     * Resolves DataType:: constants to SQL operators
+     * @param integer $type
+     * @return string
+     */
+    protected function getOperator($type)
+    {
+        $type = intval($type);
+
+        $choices = array(
+            DateType::TYPE_EQUAL            => '=',
+            DateType::TYPE_GREATER_EQUAL    => '>=',
+            DateType::TYPE_GREATER_THAN     => '>',
+            DateType::TYPE_LESS_EQUAL       => '<=',
+            DateType::TYPE_LESS_THAN        => '<',
+            DateType::TYPE_NULL             => 'NULL',
+            DateType::TYPE_NOT_NULL         => 'NOT NULL',
+        );
+
+        return isset($choices[$type]) ? $choices[$type] : '=';
+    }
+
+    /**
+     * Gets default options
+     * @return array
+     */
+    public function getDefaultOptions()
+    {
+        return array();
+    }
+
+    /**
+     * Gets render settings
+     * @return array
+     */
+    public function getRenderSettings()
+    {
+        $name = 'sonata_type_filter_date';
+
+        if ($this->time) {
+            $name .= 'time';
+        }
+
+        if ($this->range) {
+            $name .= '_range';
+        }
+
+        return array($name, array(
+            'field_type'    => $this->getFieldType(),
+            'field_options' => $this->getFieldOptions(),
+            'label'         => $this->getLabel()
+        ));
+    }
+}

+ 27 - 0
Filter/DateFilter.php

@@ -0,0 +1,27 @@
+<?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\DoctrineORMAdminBundle\Filter;
+
+class DateFilter extends AbstractDateFilter
+{
+    /**
+     * This filter has no range
+     * @var boolean
+     */
+    protected $range = false;
+
+    /**
+     * This filter does not allow filtering by time
+     * @var boolean
+     */
+    protected $time = false;
+}

+ 27 - 0
Filter/DateRangeFilter.php

@@ -0,0 +1,27 @@
+<?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\DoctrineORMAdminBundle\Filter;
+
+class DateRangeFilter extends AbstractDateFilter
+{
+    /**
+     * This is a range filter
+     * @var boolean
+     */
+    protected $range = true;
+
+    /**
+     * This filter has time
+     * @var boolean
+     */
+    protected $time = false;
+}

+ 27 - 0
Filter/DateTimeFilter.php

@@ -0,0 +1,27 @@
+<?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\DoctrineORMAdminBundle\Filter;
+
+class DateTimeFilter extends AbstractDateFilter
+{
+    /**
+     * This filter has time
+     * @var boolean
+     */
+    protected $time = true;
+
+    /**
+     * This is not a rangle filter
+     * @var boolean
+     */
+    protected $range = false;
+}

+ 27 - 0
Filter/DateTimeRangeFilter.php

@@ -0,0 +1,27 @@
+<?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\DoctrineORMAdminBundle\Filter;
+
+class DateTimeRangeFilter extends AbstractDateFilter
+{
+    /**
+     * This Filter allows filtering by time
+     * @var boolean
+     */
+    protected $time = true;
+
+    /**
+     * This is a range filter
+     * @var boolean
+     */
+    protected $range = true;
+}

+ 6 - 6
Guesser/FilterTypeGuesser.php

@@ -81,12 +81,12 @@ class FilterTypeGuesser implements TypeGuesserInterface
                 $options['field_options'] = array();
 
                 return new TypeGuess('doctrine_orm_boolean', $options, Guess::HIGH_CONFIDENCE);
-//            case 'datetime':
-//            case 'vardatetime':
-//            case 'datetimetz':
-//                return new TypeGuess('doctrine_orm_datetime', $options, Guess::HIGH_CONFIDENCE);
-//            case 'date':
-//                return new TypeGuess('doctrine_orm_date', $options, Guess::HIGH_CONFIDENCE);
+            case 'datetime':
+            case 'vardatetime':
+            case 'datetimetz':
+                return new TypeGuess('doctrine_orm_datetime', $options, Guess::HIGH_CONFIDENCE);
+            case 'date':
+                return new TypeGuess('doctrine_orm_date', $options, Guess::HIGH_CONFIDENCE);
             case 'decimal':
             case 'float':
                 return new TypeGuess('doctrine_orm_number', $options, Guess::MEDIUM_CONFIDENCE);

+ 17 - 0
Resources/config/doctrine_orm_filter_types.xml

@@ -28,6 +28,23 @@
         <service id="sonata.admin.orm.filter.type.number" class="Sonata\DoctrineORMAdminBundle\Filter\NumberFilter">
             <tag name="sonata.admin.filter.type" alias="doctrine_orm_number" />
         </service>
+        
+        <service id="sonata.admin.orm.filter.type.date" class="Sonata\DoctrineORMAdminBundle\Filter\DateFilter">
+            <tag name="sonata.admin.filter.type" alias="doctrine_orm_date" />
+        </service>
+
+        <service id="sonata.admin.orm.filter.type.date_range" class="Sonata\DoctrineORMAdminBundle\Filter\DateRangeFilter">
+            <tag name="sonata.admin.filter.type" alias="doctrine_orm_date_range" />
+        </service>
+        
+        <service id="sonata.admin.orm.filter.type.datetime" class="Sonata\DoctrineORMAdminBundle\Filter\DateTimeFilter">
+            <tag name="sonata.admin.filter.type" alias="doctrine_orm_datetime" />
+        </service>
+
+        <service id="sonata.admin.orm.filter.type.datetime_range" class="Sonata\DoctrineORMAdminBundle\Filter\DateTimeRangeFilter">
+            <tag name="sonata.admin.filter.type" alias="doctrine_orm_datetime_range" />
+        </service>
+
     </services>
 
 </container>

+ 10 - 7
Resources/doc/reference/filter_field_definition.rst

@@ -27,13 +27,16 @@ Filter types available
 
 For now, only Doctrine ORM filters are available
 
-  - doctrine_orm_boolean   : depends on the ``sonata_type_filter_default`` Form Type, renders 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, renders 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, renders yes or no field
-
+  - doctrine_orm_boolean        : depends on the ``sonata_type_filter_default`` Form Type, renders 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, renders 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, renders yes or no field
+  - doctrine_orm_date           : depends on the ``sonata_type_filter_date`` From Type, renders a date field
+  - doctrine_orm_date_range     : depends on the ``sonata_type_filter_date_range`` From Type, renders a 2 date fields
+  - doctrine_orm_datetime       : depends on the ``sonata_type_filter_datetime`` From Type, renders a datetime field
+  - doctrine_orm_datetime_range : depends on the ``sonata_type_filter_datetime_range`` From Type, renders a 2 datetime fields
 
 Example
 -------