Completed
Pull Request — master (#646)
by Grégoire
02:05
created

AbstractDateFilter::getRenderSettings()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 4
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Sonata Project package.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sonata\DoctrineORMAdminBundle\Filter;
13
14
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
15
use Sonata\AdminBundle\Form\Type\Filter\DateRangeType;
16
use Sonata\AdminBundle\Form\Type\Filter\DateType;
17
18
abstract class AbstractDateFilter extends Filter
19
{
20
    /**
21
     * Flag indicating that filter will have range.
22
     *
23
     * @var bool
24
     */
25
    protected $range = false;
26
27
    /**
28
     * Flag indicating that filter will filter by datetime instead by date.
29
     *
30
     * @var bool
31
     */
32
    protected $time = false;
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data)
38
    {
39
        // check data sanity
40
        if (!$data || !is_array($data) || !array_key_exists('value', $data)) {
41
            return;
42
        }
43
44
        if ($this->range) {
45
            // additional data check for ranged items
46
            if (!array_key_exists('start', $data['value']) || !array_key_exists('end', $data['value'])) {
47
                return;
48
            }
49
50
            if (!$data['value']['start'] && !$data['value']['end']) {
51
                return;
52
            }
53
54
            // date filter should filter records for the whole days
55
            if ($this->time === false) {
56
                if ($data['value']['start'] instanceof \DateTime) {
57
                    $data['value']['start']->setTime(0, 0, 0);
58
                }
59
                if ($data['value']['end'] instanceof \DateTime) {
60
                    $data['value']['end']->setTime(23, 59, 59);
61
                }
62
            }
63
64
            // transform types
65
            if ($this->getOption('input_type') === 'timestamp') {
66
                $data['value']['start'] = $data['value']['start'] instanceof \DateTime ? $data['value']['start']->getTimestamp() : 0;
67
                $data['value']['end'] = $data['value']['end'] instanceof \DateTime ? $data['value']['end']->getTimestamp() : 0;
68
            }
69
70
            // default type for range filter
71
            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ? DateRangeType::TYPE_BETWEEN : $data['type'];
72
73
            $startDateParameterName = $this->getNewParameterName($queryBuilder);
74
            $endDateParameterName = $this->getNewParameterName($queryBuilder);
75
76
            if ($data['type'] == DateRangeType::TYPE_NOT_BETWEEN) {
77
                $this->applyWhere($queryBuilder, sprintf('%s.%s < :%s OR %s.%s > :%s', $alias, $field, $startDateParameterName, $alias, $field, $endDateParameterName));
78
            } else {
79
                if ($data['value']['start']) {
80
                    $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '>=', $startDateParameterName));
81
                }
82
83
                if ($data['value']['end']) {
84
                    $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '<=', $endDateParameterName));
85
                }
86
            }
87
88
            if ($data['value']['start']) {
89
                $queryBuilder->setParameter($startDateParameterName, $data['value']['start']);
90
            }
91
92
            if ($data['value']['end']) {
93
                $queryBuilder->setParameter($endDateParameterName, $data['value']['end']);
94
            }
95
        } else {
96
            if (!$data['value']) {
97
                return;
98
            }
99
100
            // default type for simple filter
101
            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ? DateType::TYPE_EQUAL : $data['type'];
102
103
            // just find an operator and apply query
104
            $operator = $this->getOperator($data['type']);
105
106
            // transform types
107
            if ($this->getOption('input_type') === 'timestamp') {
108
                $data['value'] = $data['value'] instanceof \DateTime ? $data['value']->getTimestamp() : 0;
109
            }
110
111
            // null / not null only check for col
112
            if (in_array($operator, array('NULL', 'NOT NULL'))) {
113
                $this->applyWhere($queryBuilder, sprintf('%s.%s IS %s ', $alias, $field, $operator));
114
115
                return;
116
            }
117
118
            $parameterName = $this->getNewParameterName($queryBuilder);
119
120
            // date filter should filter records for the whole day
121
            if ($this->time === false && $data['type'] == DateType::TYPE_EQUAL) {
122
                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '>=', $parameterName));
123
                $queryBuilder->setParameter($parameterName, $data['value']);
124
125
                $endDateParameterName = $this->getNewParameterName($queryBuilder);
126
                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '<', $endDateParameterName));
127
                if ($this->getOption('input_type') === 'timestamp') {
128
                    $endValue = strtotime('+1 day', $data['value']);
129
                } else {
130
                    $endValue = clone $data['value'];
131
                    $endValue->add(new \DateInterval('P1D'));
132
                }
133
                $queryBuilder->setParameter($endDateParameterName, $endValue);
134
135
                return;
136
            }
137
138
            $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, $operator, $parameterName));
139
            $queryBuilder->setParameter($parameterName, $data['value']);
140
        }
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function getDefaultOptions()
147
    {
148
        return array(
149
            'input_type' => 'datetime',
150
        );
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156
    public function getRenderSettings()
157
    {
158
        $name = 'Sonata\AdminBundle\Form\Type\Filter\Date';
159
160
        if ($this->time) {
161
            $name .= 'Time';
162
        }
163
164
        if ($this->range) {
165
            $name .= 'Range';
166
        }
167
168
        $name .= 'Type';
169
170
        return array($name, array(
171
            'field_type' => $this->getFieldType(),
172
            'field_options' => $this->getFieldOptions(),
173
            'label' => $this->getLabel(),
174
        ));
175
    }
176
177
    /**
178
     * Resolves DataType:: constants to SQL operators.
179
     *
180
     * @param int $type
181
     *
182
     * @return string
183
     */
184
    protected function getOperator($type)
185
    {
186
        $type = intval($type);
187
188
        $choices = array(
189
            DateType::TYPE_EQUAL => '=',
190
            DateType::TYPE_GREATER_EQUAL => '>=',
191
            DateType::TYPE_GREATER_THAN => '>',
192
            DateType::TYPE_LESS_EQUAL => '<=',
193
            DateType::TYPE_LESS_THAN => '<',
194
            DateType::TYPE_NULL => 'NULL',
195
            DateType::TYPE_NOT_NULL => 'NOT NULL',
196
        );
197
198
        return isset($choices[$type]) ? $choices[$type] : '=';
199
    }
200
}
201