FormContractor::getFormFactory()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\DoctrinePHPCRAdminBundle\Builder;
15
16
use Doctrine\ODM\PHPCR\Mapping\ClassMetadata;
17
use Sonata\AdminBundle\Admin\AdminInterface;
18
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
19
use Sonata\AdminBundle\Builder\FormContractorInterface;
20
use Sonata\AdminBundle\Form\Type\AdminType;
21
use Sonata\AdminBundle\Form\Type\ModelType;
22
use Sonata\AdminBundle\Form\Type\ModelTypeList;
23
use Sonata\CoreBundle\Form\Type\CollectionType as DeprecatedCollectionType;
24
use Sonata\DoctrinePHPCRAdminBundle\Form\Type\TreeModelType;
25
use Sonata\Form\Type\CollectionType;
26
use Symfony\Component\Form\Extension\Core\Type\FormType;
27
use Symfony\Component\Form\FormFactoryInterface;
28
29
class FormContractor implements FormContractorInterface
30
{
31
    /**
32
     * @var FormFactoryInterface
33
     */
34
    protected $formFactory;
35
36
    public function __construct(FormFactoryInterface $formFactory)
37
    {
38
        $this->formFactory = $formFactory;
39
    }
40
41
    /**
42
     * The method defines the correct default settings for the provided FieldDescription.
43
     *
44
     * {@inheritdoc}
45
     *
46
     * @throws \RuntimeException if the $fieldDescription does not specify a type
47
     */
48
    public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription): void
49
    {
50
        $metadata = null;
51
        if ($admin->getModelManager()->hasMetadata($admin->getClass())) {
52
            /** @var ClassMetadata $metadata */
53
            $metadata = $admin->getModelManager()->getMetadata($admin->getClass());
54
55
            // set the default field mapping
56
            if (isset($metadata->mappings[$fieldDescription->getName()])) {
57
                $fieldDescription->setFieldMapping($metadata->mappings[$fieldDescription->getName()]);
58
            }
59
60
            // set the default association mapping
61
            if ($metadata->hasAssociation($fieldDescription->getName())) {
62
                $fieldDescription->setAssociationMapping($metadata->getAssociation($fieldDescription->getName()));
63
            }
64
        }
65
66
        if (!$fieldDescription->getType()) {
67
            throw new \RuntimeException(sprintf(
68
                'Please define a type for field `%s` in `%s`',
69
                $fieldDescription->getName(),
70
                \get_class($admin)
71
            ));
72
        }
73
74
        $fieldDescription->setAdmin($admin);
75
        $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'standard'));
76
77
        $mappingTypes = [
78
            ClassMetadata::MANY_TO_ONE,
79
            ClassMetadata::MANY_TO_MANY,
80
            'children',
81
            'child',
82
            'parent',
83
            'referrers',
84
        ];
85
86
        if ($metadata && $metadata->hasAssociation($fieldDescription->getName()) && \in_array($fieldDescription->getMappingType(), $mappingTypes, true)) {
87
            $admin->attachAdminClass($fieldDescription);
88
        }
89
    }
90
91
    /**
92
     * @return FormFactoryInterface
93
     */
94
    public function getFormFactory()
95
    {
96
        return $this->formFactory;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getFormBuilder($name, array $options = [])
103
    {
104
        return $this->getFormFactory()->createNamedBuilder(
105
            $name,
106
            FormType::class,
107
            null,
108
            $options
109
        );
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     *
115
     * @throws \LogicException if a sonata_type_model field does not have a
116
     *                         target model configured
117
     */
118
    public function getDefaultOptions($type, FieldDescriptionInterface $fieldDescription)
119
    {
120
        $options = [];
121
        $options['sonata_field_description'] = $fieldDescription;
122
123
        switch ($type) {
124
            case TreeModelType::class:
125
            case 'doctrine_phpcr_odm_tree':
126
                $options['class'] = $fieldDescription->getTargetEntity();
127
                $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
128
129
                break;
130
            case ModelType::class:
131
            case 'sonata_type_model':
132
            case ModelTypeList::class:
133
            case 'sonata_type_model_list':
134
                if ('child' !== $fieldDescription->getMappingType() && !$fieldDescription->getTargetEntity()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldDescription->getTargetEntity() of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
135
                    throw new \LogicException(sprintf(
136
                        'The field "%s" in class "%s" does not have a target model defined. Please specify the "targetDocument" attribute in the mapping for this class.',
137
                        $fieldDescription->getName(),
138
                        $fieldDescription->getAdmin()->getClass()
139
                    ));
140
                }
141
142
                $options['class'] = $fieldDescription->getTargetEntity();
143
                $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
144
145
                break;
146
            case AdminType::class:
147
            case 'sonata_type_admin':
148
                if (!$fieldDescription->getAssociationAdmin()) {
149
                    throw $this->getAssociationAdminException($fieldDescription);
150
                }
151
152
                $options['data_class'] = $fieldDescription->getAssociationAdmin()->getClass();
153
                $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'admin'));
154
155
                break;
156
            case DeprecatedCollectionType::class:
157
            case 'sonata_type_collection_legacy':
158
            /*
159
             * NEXT_MAJOR: Remove 'Sonata\CoreBundle\Form\Type\CollectionType' and 'sonata_type_collection_legacy'
160
             * cases when replace SonataCoreBundle by SonataFormExtension
161
             */
162
            case CollectionType::class:
163
            case 'sonata_type_collection':
164
                if (!$fieldDescription->getAssociationAdmin()) {
165
                    throw $this->getAssociationAdminException($fieldDescription);
166
                }
167
168
                $options['type'] = AdminType::class;
169
                $options['modifiable'] = true;
170
                $options['type_options'] = [
171
                    'sonata_field_description' => $fieldDescription,
172
                    'data_class' => $fieldDescription->getAssociationAdmin()->getClass(),
173
                ];
174
175
            break;
176
        }
177
178
        return $options;
179
    }
180
181
    /**
182
     * @return \LogicException
183
     */
184
    protected function getAssociationAdminException(FieldDescriptionInterface $fieldDescription)
185
    {
186
        $msg = sprintf('The current field `%s` is not linked to an admin. Please create one', $fieldDescription->getName());
187
        if (\in_array($fieldDescription->getMappingType(), [ClassMetadata::MANY_TO_ONE, ClassMetadata::MANY_TO_MANY, 'referrers'], true)) {
188
            if ($fieldDescription->getTargetEntity()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldDescription->getTargetEntity() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
189
                $msg .= " for the target document: `{$fieldDescription->getTargetEntity()}`";
190
            }
191
            $msg .= ', specify the `targetDocument` in the Reference, or the `referringDocument` in the Referrers or use the option `admin_code` to link it.';
192
        } else {
193
            $msg .= ' and use the option `admin_code` to link it.';
194
        }
195
196
        return new \LogicException($msg);
197
    }
198
}
199