Completed
Pull Request — 2.x (#556)
by Grégoire
03:14 queued 01:40
created

src/Builder/FormContractor.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 Symfony\Component\Form\FormFactoryInterface;
21
22
class FormContractor implements FormContractorInterface
23
{
24
    /**
25
     * @var FormFactoryInterface
26
     */
27
    protected $formFactory;
28
29
    public function __construct(FormFactoryInterface $formFactory)
30
    {
31
        $this->formFactory = $formFactory;
32
    }
33
34
    /**
35
     * The method defines the correct default settings for the provided FieldDescription.
36
     *
37
     * {@inheritdoc}
38
     *
39
     * @throws \RuntimeException if the $fieldDescription does not specify a type
40
     */
41
    public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
42
    {
43
        $metadata = null;
44
        if ($admin->getModelManager()->hasMetadata($admin->getClass())) {
45
            /** @var \Doctrine\ODM\PHPCR\Mapping\ClassMetadata $metadata */
46
            $metadata = $admin->getModelManager()->getMetadata($admin->getClass());
47
48
            // set the default field mapping
49
            if (isset($metadata->mappings[$fieldDescription->getName()])) {
50
                $fieldDescription->setFieldMapping($metadata->mappings[$fieldDescription->getName()]);
51
            }
52
53
            // set the default association mapping
54
            if ($metadata->hasAssociation($fieldDescription->getName())) {
55
                $fieldDescription->setAssociationMapping($metadata->getAssociation($fieldDescription->getName()));
56
            }
57
        }
58
59
        if (!$fieldDescription->getType()) {
60
            throw new \RuntimeException(sprintf(
61
                'Please define a type for field `%s` in `%s`',
62
                $fieldDescription->getName(),
63
                \get_class($admin)
64
            ));
65
        }
66
67
        $fieldDescription->setAdmin($admin);
68
        $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'standard'));
69
70
        $mappingTypes = [
71
            ClassMetadata::MANY_TO_ONE,
72
            ClassMetadata::MANY_TO_MANY,
73
            'children',
74
            'child',
75
            'parent',
76
            'referrers',
77
        ];
78
79
        if ($metadata && $metadata->hasAssociation($fieldDescription->getName()) && \in_array($fieldDescription->getMappingType(), $mappingTypes, true)) {
80
            $admin->attachAdminClass($fieldDescription);
81
        }
82
    }
83
84
    /**
85
     * @return FormFactoryInterface
86
     */
87
    public function getFormFactory()
88
    {
89
        return $this->formFactory;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95
    public function getFormBuilder($name, array $options = [])
96
    {
97
        return $this->getFormFactory()->createNamedBuilder(
98
            $name,
99
            'Symfony\Component\Form\Extension\Core\Type\FormType',
100
            null,
101
            $options);
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     *
107
     * @throws \LogicException if a sonata_type_model field does not have a
108
     *                         target model configured
109
     */
110
    public function getDefaultOptions($type, FieldDescriptionInterface $fieldDescription)
111
    {
112
        $options = [];
113
        $options['sonata_field_description'] = $fieldDescription;
114
115
        switch ($type) {
116
            case 'Sonata\DoctrinePHPCRAdminBundle\Form\Type\TreeModelType':
117
            case 'doctrine_phpcr_odm_tree':
118
                $options['class'] = $fieldDescription->getTargetEntity();
119
                $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
120
121
                break;
122
            case 'Sonata\AdminBundle\Form\Type\ModelType':
123
            case 'sonata_type_model':
124
            case 'Sonata\AdminBundle\Form\Type\ModelTypeList':
125
            case 'sonata_type_model_list':
126
                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...
127
                    throw new \LogicException(sprintf(
128
                        'The field "%s" in class "%s" does not have a target model defined. Please specify the "targetDocument" attribute in the mapping for this class.',
129
                        $fieldDescription->getName(),
130
                        $fieldDescription->getAdmin()->getClass()
131
                    ));
132
                }
133
134
                $options['class'] = $fieldDescription->getTargetEntity();
135
                $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
136
137
                break;
138
            case 'Sonata\AdminBundle\Form\Type\AdminType':
139
            case 'sonata_type_admin':
140
                if (!$fieldDescription->getAssociationAdmin()) {
141
                    throw $this->getAssociationAdminException($fieldDescription);
142
                }
143
144
                $options['data_class'] = $fieldDescription->getAssociationAdmin()->getClass();
145
                $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'admin'));
146
147
                break;
148
            case 'Sonata\CoreBundle\Form\Type\CollectionType':
149
            case 'sonata_type_collection_legacy':
150
            /*
151
             * NEXT_MAJOR: Remove 'Sonata\CoreBundle\Form\Type\CollectionType' and 'sonata_type_collection_legacy'
152
             * cases when replace SonataCoreBundle by SonataFormExtension
153
             */
154
            case 'Sonata\Form\Type\CollectionType':
155
            case 'sonata_type_collection':
156
                if (!$fieldDescription->getAssociationAdmin()) {
157
                    throw $this->getAssociationAdminException($fieldDescription);
158
                }
159
160
                $options['type'] = 'Sonata\AdminBundle\Form\Type\AdminType';
161
                $options['modifiable'] = true;
162
                $options['type_options'] = [
163
                    'sonata_field_description' => $fieldDescription,
164
                    'data_class' => $fieldDescription->getAssociationAdmin()->getClass(),
165
                ];
166
167
            break;
168
        }
169
170
        return $options;
171
    }
172
173
    /**
174
     * @return \LogicException
175
     */
176
    protected function getAssociationAdminException(FieldDescriptionInterface $fieldDescription)
177
    {
178
        $msg = sprintf('The current field `%s` is not linked to an admin. Please create one', $fieldDescription->getName());
179
        if (\in_array($fieldDescription->getMappingType(), [ClassMetadata::MANY_TO_ONE, ClassMetadata::MANY_TO_MANY, 'referrers'], true)) {
180
            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...
181
                $msg .= " for the target document: `{$fieldDescription->getTargetEntity()}`";
182
            }
183
            $msg .= ', specify the `targetDocument` in the Reference, or the `referringDocument` in the Referrers or use the option `admin_code` to link it.';
184
        } else {
185
            $msg .= ' and use the option `admin_code` to link it.';
186
        }
187
188
        return new \LogicException($msg);
189
    }
190
}
191