Completed
Push — master ( f335a7...6a7f39 )
by Grégoire
12s
created

AbstractDateFilter   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 1
dl 0
loc 181
rs 8.2857
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getOperator() 0 16 2
F filter() 0 105 31
A getDefaultOptions() 0 6 1
B getRenderSettings() 0 18 5
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\DateTimeRangeType;
17
use Sonata\AdminBundle\Form\Type\Filter\DateTimeType;
18
use Sonata\AdminBundle\Form\Type\Filter\DateType;
19
20
abstract class AbstractDateFilter extends Filter
21
{
22
    /**
23
     * Flag indicating that filter will have range.
24
     *
25
     * @var bool
26
     */
27
    protected $range = false;
28
29
    /**
30
     * Flag indicating that filter will filter by datetime instead by date.
31
     *
32
     * @var bool
33
     */
34
    protected $time = false;
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data)
40
    {
41
        // check data sanity
42
        if (!$data || !is_array($data) || !array_key_exists('value', $data)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
43
            return;
44
        }
45
46
        if ($this->range) {
47
            // additional data check for ranged items
48
            if (!array_key_exists('start', $data['value']) || !array_key_exists('end', $data['value'])) {
49
                return;
50
            }
51
52
            if (!$data['value']['start'] && !$data['value']['end']) {
53
                return;
54
            }
55
56
            // date filter should filter records for the whole days
57
            if (false === $this->time) {
58
                if ($data['value']['start'] instanceof \DateTime) {
59
                    $data['value']['start']->setTime(0, 0, 0);
60
                }
61
                if ($data['value']['end'] instanceof \DateTime) {
62
                    $data['value']['end']->setTime(23, 59, 59);
63
                }
64
            }
65
66
            // transform types
67
            if ('timestamp' === $this->getOption('input_type')) {
68
                $data['value']['start'] = $data['value']['start'] instanceof \DateTime ? $data['value']['start']->getTimestamp() : 0;
69
                $data['value']['end'] = $data['value']['end'] instanceof \DateTime ? $data['value']['end']->getTimestamp() : 0;
70
            }
71
72
            // default type for range filter
73
            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ? DateRangeType::TYPE_BETWEEN : $data['type'];
74
75
            $startDateParameterName = $this->getNewParameterName($queryBuilder);
76
            $endDateParameterName = $this->getNewParameterName($queryBuilder);
77
78
            if (DateRangeType::TYPE_NOT_BETWEEN == $data['type']) {
79
                $this->applyWhere($queryBuilder, sprintf('%s.%s < :%s OR %s.%s > :%s', $alias, $field, $startDateParameterName, $alias, $field, $endDateParameterName));
80
            } else {
81
                if ($data['value']['start']) {
82
                    $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '>=', $startDateParameterName));
83
                }
84
85
                if ($data['value']['end']) {
86
                    $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '<=', $endDateParameterName));
87
                }
88
            }
89
90
            if ($data['value']['start']) {
91
                $queryBuilder->setParameter($startDateParameterName, $data['value']['start']);
92
            }
93
94
            if ($data['value']['end']) {
95
                $queryBuilder->setParameter($endDateParameterName, $data['value']['end']);
96
            }
97
        } else {
98
            if (!$data['value']) {
99
                return;
100
            }
101
102
            // default type for simple filter
103
            $data['type'] = !isset($data['type']) || !is_numeric($data['type']) ? DateType::TYPE_EQUAL : $data['type'];
104
105
            // just find an operator and apply query
106
            $operator = $this->getOperator($data['type']);
107
108
            // transform types
109
            if ('timestamp' === $this->getOption('input_type')) {
110
                $data['value'] = $data['value'] instanceof \DateTime ? $data['value']->getTimestamp() : 0;
111
            }
112
113
            // null / not null only check for col
114
            if (in_array($operator, ['NULL', 'NOT NULL'])) {
115
                $this->applyWhere($queryBuilder, sprintf('%s.%s IS %s ', $alias, $field, $operator));
116
117
                return;
118
            }
119
120
            $parameterName = $this->getNewParameterName($queryBuilder);
121
122
            // date filter should filter records for the whole day
123
            if (false === $this->time && DateType::TYPE_EQUAL == $data['type']) {
124
                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '>=', $parameterName));
125
                $queryBuilder->setParameter($parameterName, $data['value']);
126
127
                $endDateParameterName = $this->getNewParameterName($queryBuilder);
128
                $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, '<', $endDateParameterName));
129
                if ('timestamp' === $this->getOption('input_type')) {
130
                    $endValue = strtotime('+1 day', $data['value']);
131
                } else {
132
                    $endValue = clone $data['value'];
133
                    $endValue->add(new \DateInterval('P1D'));
134
                }
135
                $queryBuilder->setParameter($endDateParameterName, $endValue);
136
137
                return;
138
            }
139
140
            $this->applyWhere($queryBuilder, sprintf('%s.%s %s :%s', $alias, $field, $operator, $parameterName));
141
            $queryBuilder->setParameter($parameterName, $data['value']);
142
        }
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function getDefaultOptions()
149
    {
150
        return [
151
            'input_type' => 'datetime',
152
        ];
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function getRenderSettings()
159
    {
160
        $name = DateType::class;
161
162
        if ($this->time && $this->range) {
163
            $name = DateTimeRangeType::class;
164
        } elseif ($this->time) {
165
            $name = DateTimeType::class;
166
        } elseif ($this->range) {
167
            $name = DateRangeType::class;
168
        }
169
170
        return [$name, [
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 = [
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