Completed
Pull Request — 3.x (#662)
by
unknown
02:36
created

FormContractor::checkFormClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
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\Builder;
13
14
use Doctrine\ORM\Mapping\ClassMetadataInfo;
15
use Sonata\AdminBundle\Admin\AdminInterface;
16
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
17
use Sonata\AdminBundle\Builder\FormContractorInterface;
18
use Symfony\Component\Form\FormFactoryInterface;
19
20
class FormContractor implements FormContractorInterface
21
{
22
    /**
23
     * NEXT_MAJOR: remove this property.
24
     *
25
     * @deprecated since version 3.0.4, to be removed in 4.0
26
     *
27
     * @var FormFactoryInterface
28
     */
29
    protected $fieldFactory;
30
31
    /**
32
     * @var FormFactoryInterface
33
     */
34
    protected $formFactory;
35
36
    /**
37
     * @param FormFactoryInterface $formFactory
38
     */
39
    public function __construct(FormFactoryInterface $formFactory)
40
    {
41
        $this->formFactory = $formFactory;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
48
    {
49
        if ($admin->getModelManager()->hasMetadata($admin->getClass())) {
50
            $metadata = $admin->getModelManager()->getMetadata($admin->getClass());
51
52
            // set the default field mapping
53
            if (isset($metadata->fieldMappings[$fieldDescription->getName()])) {
54
                $fieldDescription->setFieldMapping($metadata->fieldMappings[$fieldDescription->getName()]);
55
            }
56
57
            // set the default association mapping
58
            if (isset($metadata->associationMappings[$fieldDescription->getName()])) {
59
                $fieldDescription->setAssociationMapping($metadata->associationMappings[$fieldDescription->getName()]);
60
            }
61
        }
62
63
        if (!$fieldDescription->getType()) {
64
            throw new \RuntimeException(sprintf(
65
                'Please define a type for field `%s` in `%s`',
66
                $fieldDescription->getName(),
67
                get_class($admin)
68
            ));
69
        }
70
71
        $fieldDescription->setAdmin($admin);
72
        $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'standard'));
73
74
        if ($this->hasAssociation($fieldDescription) || $fieldDescription->getOption('admin_code')) {
75
            $admin->attachAdminClass($fieldDescription);
76
        }
77
    }
78
79
    /**
80
     * @return FormFactoryInterface
81
     */
82
    public function getFormFactory()
83
    {
84
        return $this->formFactory;
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function getFormBuilder($name, array $options = array())
91
    {
92
        // NEXT_MAJOR: Remove this line when drop Symfony <2.8 support
93
        $formType = method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')
94
            ? 'Symfony\Component\Form\Extension\Core\Type\FormType' : 'form';
95
96
        return $this->getFormFactory()->createNamedBuilder($name, $formType, null, $options);
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getDefaultOptions($type, FieldDescriptionInterface $fieldDescription)
103
    {
104
        $options = array();
105
        $options['sonata_field_description'] = $fieldDescription;
106
107
        // NEXT_MAJOR: Check only against FQCNs when dropping support for Symfony <2.8
108
        if ($this->checkFormType($type, array(
109
                'sonata_type_model',
110
                'sonata_type_model_list',
111
                'sonata_type_model_hidden',
112
                'sonata_type_model_autocomplete',
113
            )) || $this->checkFormClass($type, array(
114
                'Sonata\AdminBundle\Form\Type\ModelType',
115
                'Sonata\AdminBundle\Form\Type\ModelTypeList',
116
                'Sonata\AdminBundle\Form\Type\ModelListType',
117
                'Sonata\AdminBundle\Form\Type\ModelHiddenType',
118
                'Sonata\AdminBundle\Form\Type\ModelAutocompleteType',
119
            ))) {
120
            if ($fieldDescription->getOption('edit') === 'list') {
121
                throw new \LogicException(
122
                    'The `sonata_type_model` type does not accept an `edit` option anymore,'
123
                    .' please review the UPGRADE-2.1.md file from the SonataAdminBundle'
124
                );
125
            }
126
127
            $options['class'] = $fieldDescription->getTargetEntity();
128
            $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
129
130
            // NEXT_MAJOR: Check only against FQCNs when dropping support for Symfony <2.8
131
            if ($this->checkFormType($type, array('sonata_type_model_autocomplete')) || $this->checkFormClass($type, array('Sonata\AdminBundle\Form\Type\ModelAutocompleteType'))) {
132
                if (!$fieldDescription->getAssociationAdmin()) {
133
                    throw new \RuntimeException(sprintf(
134
                        'The current field `%s` is not linked to an admin.'
135
                        .' Please create one for the target entity: `%s`',
136
                        $fieldDescription->getName(),
137
                        $fieldDescription->getTargetEntity()
138
                    ));
139
                }
140
            }
141
            // NEXT_MAJOR: Check only against FQCNs when dropping support for Symfony <2.8
142
        } elseif ($this->checkFormType($type, array('sonata_type_admin')) || $this->checkFormClass($type, array('Sonata\AdminBundle\Form\Type\AdminType'))) {
143
            if (!$fieldDescription->getAssociationAdmin()) {
144
                throw new \RuntimeException(sprintf(
145
                    'The current field `%s` is not linked to an admin.'
146
                    .' Please create one for the target entity : `%s`',
147
                    $fieldDescription->getName(),
148
                    $fieldDescription->getTargetEntity()
149
                ));
150
            }
151
152
            if (!in_array($fieldDescription->getMappingType(), array(ClassMetadataInfo::ONE_TO_ONE, ClassMetadataInfo::MANY_TO_ONE))) {
153
                throw new \RuntimeException(sprintf(
154
                    'You are trying to add `sonata_type_admin` field `%s` which is not One-To-One or  Many-To-One.'
155
                    .' Maybe you want `sonata_type_collection` instead?',
156
                    $fieldDescription->getName()
157
                ));
158
            }
159
160
            // set sensitive default value to have a component working fine out of the box
161
            $options['btn_add'] = false;
162
            $options['delete'] = false;
163
164
            $options['data_class'] = $fieldDescription->getAssociationAdmin()->getClass();
165
            $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'admin'));
166
            // NEXT_MAJOR: Check only against FQCNs when dropping support for Symfony <2.8
167
        } elseif ($this->checkFormType($type, array('sonata_type_collection')) || $this->checkFormClass($type, array('Sonata\CoreBundle\Form\Type\CollectionType'))) {
168
            if (!$fieldDescription->getAssociationAdmin()) {
169
                throw new \RuntimeException(sprintf(
170
                    'The current field `%s` is not linked to an admin.'
171
                    .' Please create one for the target entity : `%s`',
172
                    $fieldDescription->getName(),
173
                    $fieldDescription->getTargetEntity()
174
                ));
175
            }
176
177
            $options['type'] = 'sonata_type_admin';
178
            $options['modifiable'] = true;
179
            $options['type_options'] = array(
180
                'sonata_field_description' => $fieldDescription,
181
                'data_class' => $fieldDescription->getAssociationAdmin()->getClass(),
182
            );
183
        }
184
185
        return $options;
186
    }
187
188
    /**
189
     * @param FieldDescriptionInterface $fieldDescription
190
     *
191
     * @return bool
192
     */
193
    private function hasAssociation(FieldDescriptionInterface $fieldDescription)
194
    {
195
        return in_array($fieldDescription->getMappingType(), array(
196
            ClassMetadataInfo::ONE_TO_MANY,
197
            ClassMetadataInfo::MANY_TO_MANY,
198
            ClassMetadataInfo::MANY_TO_ONE,
199
            ClassMetadataInfo::ONE_TO_ONE,
200
        ));
201
    }
202
203
    /**
204
     * NEXT_MAJOR: See next major comments above, this method should be removed when dropping support for Symfony <2.8.
205
     *
206
     * @param string $type
207
     * @param array  $types
208
     *
209
     * @return bool
210
     */
211
    private function checkFormType($type, $types)
212
    {
213
        return in_array($type, $types, true);
214
    }
215
216
    /**
217
     * @param string $type
218
     * @param array  $classes
219
     *
220
     * @return array
221
     */
222
    private function checkFormClass($type, $classes)
223
    {
224
        return array_filter($classes, function ($subclass) use ($type) {
225
            return is_a($type, $subclass, true);
226
        });
227
    }
228
}
229