Completed
Pull Request — master (#704)
by Grégoire
03:29
created

ModelFilter   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 20
c 2
b 1
f 0
lcom 1
cbo 3
dl 0
loc 141
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultOptions() 0 11 1
A getRenderSettings() 0 10 1
B filter() 0 16 7
B handleMultiple() 0 30 5
A association() 0 19 2
A getParentAlias() 0 16 4
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 Doctrine\Common\Collections\Collection;
15
use Doctrine\ORM\Mapping\ClassMetadataInfo;
16
use Doctrine\ORM\QueryBuilder;
17
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
18
use Sonata\CoreBundle\Form\Type\EqualType;
19
20
class ModelFilter extends Filter
21
{
22
    /**
23
     * {@inheritdoc}
24
     */
25
    public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data)
26
    {
27
        if (!$data || !is_array($data) || !array_key_exists('value', $data) || empty($data['value'])) {
28
            return;
29
        }
30
31
        if ($data['value'] instanceof Collection) {
32
            $data['value'] = $data['value']->toArray();
33
        }
34
35
        if (!is_array($data['value'])) {
36
            $data['value'] = array($data['value']);
37
        }
38
39
        $this->handleMultiple($queryBuilder, $alias, $data);
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function getDefaultOptions()
46
    {
47
        return array(
48
            'mapping_type' => false,
49
            'field_name' => false,
50
            'field_type' => 'Symfony\Bridge\Doctrine\Form\Type\EntityType',
51
            'field_options' => array(),
52
            'operator_type' => 'Sonata\CoreBundle\Form\Type\EqualType',
53
            'operator_options' => array(),
54
        );
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function getRenderSettings()
61
    {
62
        return array('Sonata\AdminBundle\Form\Type\Filter\DefaultType', array(
63
            'field_type' => $this->getFieldType(),
64
            'field_options' => $this->getFieldOptions(),
65
            'operator_type' => $this->getOption('operator_type'),
66
            'operator_options' => $this->getOption('operator_options'),
67
            'label' => $this->getLabel(),
68
        ));
69
    }
70
71
    /**
72
     * For the record, the $alias value is provided by the association method (and the entity join method)
73
     *  so the field value is not used here.
74
     *
75
     * @param ProxyQueryInterface|QueryBuilder $queryBuilder
76
     * @param string                           $alias
77
     * @param mixed                            $data
78
     *
79
     * @return mixed
80
     */
81
    protected function handleMultiple(ProxyQueryInterface $queryBuilder, $alias, $data)
82
    {
83
        if (count($data['value']) == 0) {
84
            return;
85
        }
86
87
        $parameterName = $this->getNewParameterName($queryBuilder);
88
89
        if (isset($data['type']) && $data['type'] == EqualType::TYPE_IS_NOT_EQUAL) {
90
            $or = $queryBuilder->expr()->orX();
91
92
            $or->add($queryBuilder->expr()->notIn($alias, ':'.$parameterName));
93
94
            if ($this->getOption('mapping_type') === ClassMetadataInfo::MANY_TO_MANY) {
95
                $or->add(
96
                    sprintf('%s.%s IS EMPTY', $this->getParentAlias($queryBuilder, $alias), $this->getFieldName())
97
                );
98
            } else {
99
                $or->add($queryBuilder->expr()->isNull(
100
                    sprintf('IDENTITY(%s.%s)', $this->getParentAlias($queryBuilder, $alias), $this->getFieldName())
101
                ));
102
            }
103
104
            $this->applyWhere($queryBuilder, $or);
105
        } else {
106
            $this->applyWhere($queryBuilder, $queryBuilder->expr()->in($alias, ':'.$parameterName));
107
        }
108
109
        $queryBuilder->setParameter($parameterName, $data['value']);
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    protected function association(ProxyQueryInterface $queryBuilder, $data)
116
    {
117
        $types = array(
118
            ClassMetadataInfo::ONE_TO_ONE,
119
            ClassMetadataInfo::ONE_TO_MANY,
120
            ClassMetadataInfo::MANY_TO_MANY,
121
            ClassMetadataInfo::MANY_TO_ONE,
122
        );
123
124
        if (!in_array($this->getOption('mapping_type'), $types)) {
125
            throw new \RuntimeException('Invalid mapping type');
126
        }
127
128
        $associationMappings = $this->getParentAssociationMappings();
129
        $associationMappings[] = $this->getAssociationMapping();
130
        $alias = $queryBuilder->entityJoin($associationMappings);
131
132
        return array($alias, false);
133
    }
134
135
    /**
136
     * Retrieve the parent alias for given alias.
137
     * Root alias for direct association or entity joined alias for association depth >= 2.
138
     *
139
     * @param ProxyQueryInterface $queryBuilder
140
     * @param string              $alias
141
     *
142
     * @return string
143
     */
144
    private function getParentAlias(ProxyQueryInterface $queryBuilder, $alias)
145
    {
146
        $parentAlias = $rootAlias = current($queryBuilder->getRootAliases());
147
        $joins = $queryBuilder->getDQLPart('join');
148
        if (isset($joins[$rootAlias])) {
149
            foreach ($joins[$rootAlias] as $join) {
150
                if ($join->getAlias() == $alias) {
151
                    $parts = explode('.', $join->getJoin());
152
                    $parentAlias = $parts[0];
153
                    break;
154
                }
155
            }
156
        }
157
158
        return $parentAlias;
159
    }
160
}
161