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