Completed
Pull Request — 3.x (#683)
by
unknown
02:05
created

ModelFilter::getParentAlias()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 16
rs 9.2
cc 4
eloc 10
nc 4
nop 2
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
28
        if (!$data || !is_array($data) || !array_key_exists('value', $data) || empty($data['value'])) {
29
            return;
30
        }
31
32
        if ($data['value'] instanceof Collection) {
33
            $data['value'] = $data['value']->toArray();
34
        }
35
36
        if (!is_array($data['value'])) {
37
            $data['value'] = array($data['value']);
38
        }
39
40
        $this->handleMultiple($queryBuilder, $alias, $data);
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getDefaultOptions()
47
    {
48
        return array(
49
            'mapping_type' => false,
50
            'field_name' => false,
51
            'field_type' => method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')
52
                ? 'Symfony\Bridge\Doctrine\Form\Type\EntityType'
53
                : 'entity', // NEXT_MAJOR: Remove ternary (when requirement of Symfony is >= 2.8)
54
            'field_options' => array(),
55
            'operator_type' => method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')
56
                ? 'Sonata\CoreBundle\Form\Type\EqualType'
57
                : 'sonata_type_equal', // NEXT_MAJOR: Remove ternary (when requirement of Symfony is >= 2.8)
58
            'operator_options' => array(),
59
        );
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function getRenderSettings()
66
    {
67
        // NEXT_MAJOR: Remove this line when drop Symfony <2.8 support
68
        $type = method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')
69
            ? 'Sonata\AdminBundle\Form\Type\Filter\DefaultType'
70
            : 'sonata_type_filter_default';
71
72
        return array($type, array(
73
            'field_type' => $this->getFieldType(),
74
            'field_options' => $this->getFieldOptions(),
75
            'operator_type' => $this->getOption('operator_type'),
76
            'operator_options' => $this->getOption('operator_options'),
77
            'label' => $this->getLabel(),
78
        ));
79
    }
80
81
    /**
82
     * For the record, the $alias value is provided by the association method (and the entity join method)
83
     *  so the field value is not used here.
84
     *
85
     * @param ProxyQueryInterface|QueryBuilder $queryBuilder
86
     * @param string                           $alias
87
     * @param mixed                            $data
88
     *
89
     * @return mixed
90
     */
91
    protected function handleMultiple(ProxyQueryInterface $queryBuilder, $alias, $data)
92
    {
93
        if (count($data['value']) == 0) {
94
            return;
95
        }
96
97
        $parameterName = $this->getNewParameterName($queryBuilder);
98
99
        if (isset($data['type']) && $data['type'] == EqualType::TYPE_IS_NOT_EQUAL) {
100
            $or = $queryBuilder->expr()->orX();
101
102
            $or->add($queryBuilder->expr()->notIn($alias, ':'.$parameterName));
103
104
            $or->add($queryBuilder->expr()->isNull(
105
                sprintf('IDENTITY(%s.%s)', $this->getParentAlias($queryBuilder, $alias), $this->getFieldName())
106
            ));
107
108
            $this->applyWhere($queryBuilder, $or);
109
        } else {
110
            $this->applyWhere($queryBuilder, $queryBuilder->expr()->in($alias, ':'.$parameterName));
111
        }
112
113
        $queryBuilder->setParameter($parameterName, $data['value']);
114
    }
115
116
    /**
117
     * @param ProxyQueryInterface $queryBuilder
118
     * @param $alias
119
     *
120
     * @return mixed
121
     */
122
    protected function getParentAlias(ProxyQueryInterface $queryBuilder, $alias)
123
    {
124
        $parentAlias = $rootAlias = current($queryBuilder->getRootAliases());
125
        $joins = $queryBuilder->getDQLPart('join');
126
        if (isset($joins[$rootAlias])) {
127
            foreach ($joins[$rootAlias] as $join) {
128
                if ($join->getAlias() == $alias) {
129
                    $parts = explode('.', $join->getJoin());
130
                    $parentAlias = $parts[0];
131
                    break;
132
                }
133
            }
134
        }
135
136
        return $parentAlias;
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    protected function association(ProxyQueryInterface $queryBuilder, $data)
143
    {
144
        $types = array(
145
            ClassMetadataInfo::ONE_TO_ONE,
146
            ClassMetadataInfo::ONE_TO_MANY,
147
            ClassMetadataInfo::MANY_TO_MANY,
148
            ClassMetadataInfo::MANY_TO_ONE,
149
        );
150
151
        if (!in_array($this->getOption('mapping_type'), $types)) {
152
            throw new \RuntimeException('Invalid mapping type');
153
        }
154
155
        $associationMappings = $this->getParentAssociationMappings();
156
        $associationMappings[] = $this->getAssociationMapping();
157
        $alias = $queryBuilder->entityJoin($associationMappings);
158
159
        return array($alias, false);
160
    }
161
}
162