Passed
Push — master ( e85a2d...ea8174 )
by Rafael
07:43
created

resolveFormFieldDefinition()   F

Complexity

Conditions 13
Paths 1536

Size

Total Lines 58
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 18.7214

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 58
ccs 23
cts 34
cp 0.6765
rs 3.1873
cc 13
eloc 34
nc 1536
nop 2
crap 18.7214

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Definition\Extension;
12
13
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
14
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
15
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
16
use Symfony\Component\Form\Extension\Core\Type\EmailType;
17
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
18
use Symfony\Component\Form\Extension\Core\Type\NumberType;
19
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
20
use Symfony\Component\Form\Extension\Core\Type\TextType;
21
use Symfony\Component\Form\FormFactory;
22
use Symfony\Component\Form\FormInterface;
23
use Ynlo\GraphQLBundle\Definition\ArgumentDefinition;
24
use Ynlo\GraphQLBundle\Definition\DefinitionInterface;
25
use Ynlo\GraphQLBundle\Definition\FieldDefinition;
26
use Ynlo\GraphQLBundle\Definition\InputObjectDefinition;
27
use Ynlo\GraphQLBundle\Definition\MutationDefinition;
28
use Ynlo\GraphQLBundle\Definition\NodeAwareDefinitionInterface;
29
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
30
use Ynlo\GraphQLBundle\Form\Type\GraphQLType;
31
use Ynlo\GraphQLBundle\Form\Type\IDType;
32
use Ynlo\GraphQLBundle\Type\Types;
33
use Ynlo\GraphQLBundle\Util\ClassUtils;
34
use Ynlo\GraphQLBundle\Util\TypeUtil;
35
36
/**
37
 * MutationFormResolverExtension
38
 */
39
class MutationFormResolverExtension extends AbstractDefinitionExtension
40
{
41
    /**
42
     * @var FormFactory
43
     */
44
    protected $formFactory;
45
46
    /**
47
     * @param FormFactory $formFactory
48
     */
49 21
    public function __construct(FormFactory $formFactory)
50
    {
51 21
        $this->formFactory = $formFactory;
52 21
    }
53
54
    /**
55
     * {@inheritDoc}
56
     */
57 21
    public function getName(): string
58
    {
59 21
        return 'form';
60
    }
61
62
    /**
63
     * {@inheritDoc}
64
     */
65 21
    public function buildConfig(ArrayNodeDefinition $root)
66
    {
67
        $config = $root
68 21
            ->info('Resolve the form to use as input for mutations')
69 21
            ->addDefaultsIfNotSet()
70 21
            ->canBeDisabled()
71 21
            ->children();
72
73 21
        $config->variableNode('type')
74 21
               ->defaultNull()
75 21
               ->info(
76 21
                   'Specify the form type to use,
77
[string] Name of the form type to use
78
[true|null] The form will be automatically resolved to ...Bundle\Form\Input\{Node}\{MutationName}Input.
79
[true] Throw a exception if the form can`t be located
80
[false] The form is not required and should not be resolved'
81
               );
82 21
        $config->variableNode('options')->defaultValue([])->info('Form options');
83 21
        $config->variableNode('argument')
84 21
               ->defaultValue('input')
85 21
               ->info('Name of the argument to use as input');
86
87 21
        $config->booleanNode('client_mutation_id')
88 21
               ->defaultTrue()
89 21
               ->info('Automatically add a field called clientMutationId');
90 21
    }
91
92
    /**
93
     * {@inheritDoc}
94
     */
95 21
    public function configure(DefinitionInterface $definition, Endpoint $endpoint, array $config)
96
    {
97 21
        if (!$config || !$config['enabled'] || !$definition instanceof MutationDefinition) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $config of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
98 21
            return;
99
        }
100
101 21
        $formType = $config['type'] ?? null;
102
103
        //the related class is used to match a form using naming conventions
104 21
        $relatedClass = null;
105 21
        if ($definition instanceof NodeAwareDefinitionInterface && $definition->getNode()) {
106 21
            $relatedClass = $definition->getNode();
107 21
            if ($class = $endpoint->getClassForType($relatedClass)) {
108 21
                $relatedClass = $class;
109
            }
110
        } elseif ($definition->getResolver()) {
111
            $relatedClass = $definition->getResolver();
112
        }
113
114
        //try find the form using a related class
115 21
        if ($relatedClass && (!$formType || true === $formType)) {
116 21
            $bundleNamespace = ClassUtils::relatedBundleNamespace($relatedClass);
117 21
            $formClass = ClassUtils::applyNamingConvention(
118 21
                $bundleNamespace,
119 21
                'Form\Input',
120 21
                $definition->getNode(),
121 21
                ucfirst($definition->getName()),
122 21
                'Input'
123
            );
124 21
            if (class_exists($formClass)) {
125 21
                $formType = $formClass;
126
            } elseif (true === $formType) {
127
                $error = sprintf(
128
                    'Can`t find a valid input form type to use in "%s".
129
                         Create the form "%s" or specify a custom form',
130
                    $definition->getName(),
131
                    $formClass
132
                );
133
                throw new \Exception($error);
134
            }
135
        }
136
137 21
        if ($formType) {
138 21
            $config['type'] = $formType;
139
140 21
            $form = $this->formFactory->create($formType, null, $config['options'] ?? []);
141 21
            $inputObject = $this->createFormInputObject($endpoint, $form, ucfirst($definition->getName()));
142 21
            $endpoint->addType($inputObject);
143
144 21
            $input = new ArgumentDefinition();
145 21
            $input->setName($config['argument']);
146 21
            $input->setType($inputObject->getName());
147
148 21
            if ($config['client_mutation_id']) {
149 21
                $clientMutationId = new FieldDefinition();
150 21
                $clientMutationId->setName('clientMutationId');
151 21
                $clientMutationId->setType(Types::STRING);
152 21
                $clientMutationId->setDescription('A unique identifier for the client performing the mutation.');
153 21
                $inputObject->prependField($clientMutationId);
154
            }
155
156 21
            $definition->addArgument($input);
157 21
            $definition->setMeta('form', $config);
158
        }
159 21
    }
160
161
    /**
162
     * @param Endpoint      $endpoint
163
     * @param FormInterface $form
164
     * @param string        $name
165
     *
166
     * @return InputObjectDefinition
167
     */
168 21
    public function createFormInputObject(Endpoint $endpoint, FormInterface $form, $name)
169
    {
170 21
        $inputObject = new InputObjectDefinition();
171 21
        $inputObject->setName($name.'Input');
172
173 21
        foreach ($form->all() as $formField) {
174 21
            $field = new FieldDefinition();
175 21
            $field->setName($formField->getConfig()->getOption('label') ?? $formField->getName());
176 21
            $field->setNonNull($formField->isRequired());
177 21
            $field->setOriginName($formField->getName());
178
179 21
            if ($formField->all()) {
180 21
                $childName = $name.ucfirst($formField->getName());
181 21
                $child = $this->createFormInputObject($endpoint, $formField, $childName);
182 21
                $endpoint->addType($child);
183 21
                $field->setType($child->getName());
184 21
            } elseif (is_a($formField->getConfig()->getType()->getInnerType(), CollectionType::class)) {
185
                $childName = $name.ucfirst($formField->getName());
186
                $childFormType = $formField->getConfig()->getOptions()['entry_type'];
187
                $childFormOptions = $formField->getConfig()->getOptions()['entry_options'];
188
                $childForm = $this->formFactory->create($childFormType, null, $childFormOptions ?? []);
189
                $child = $this->createFormInputObject($endpoint, $childForm, $childName);
190
                $field->setType($child->getName());
191
                $field->setList(true);
192
                $endpoint->add($child);
193
            } else {
194 21
                $this->resolveFormFieldDefinition($field, $formField);
195
            }
196
197 21
            $inputObject->addField($field);
198
        }
199
200 21
        return $inputObject;
201
    }
202
203
    /**
204
     * @param FieldDefinition $field
205
     * @param FormInterface   $form
206
     */
207 21
    public function resolveFormFieldDefinition(FieldDefinition $field, FormInterface $form)
208
    {
209 21
        $type = null;
210 21
        $resolver = $form->getConfig()->getType()->getOptionsResolver();
211 21
        if ($resolver->hasDefault('graphql_type')) {
212
            $type = $resolver->resolve([])['graphql_type'];
213
            $field->setList(TypeUtil::isTypeList($type));
214
            $type = TypeUtil::normalize($type);
215
        }
216
217 21
        if (is_a($form->getConfig()->getType()->getInnerType(), GraphQLType::class, true)) {
218 21
            $type = $form->getConfig()->getOptions()['graphql_type'];
219 21
            $field->setList(TypeUtil::isTypeList($type));
220 21
            $type = TypeUtil::normalize($type);
221
        }
222
223 21
        if (is_a($form->getConfig()->getType()->getInnerType(), IDType::class, true)) {
224 21
            if ($form->getConfig()->hasOption('multiple') && $form->getConfig()->getOption('multiple')) {
225 21
                $field->setList(true);
226
            }
227 21
            $type = Types::ID;
228
        }
229
230 21
        if (is_a($form->getConfig()->getType()->getInnerType(), TextType::class, true)) {
231 21
            $type = Types::STRING;
232
        }
233
234 21
        if (is_a($form->getConfig()->getType()->getInnerType(), TextareaType::class, true)) {
235
            $type = Types::STRING;
236
        }
237
238 21
        if (is_a($form->getConfig()->getType()->getInnerType(), EmailType::class, true)) {
239 21
            $type = Types::STRING;
240
        }
241
242 21
        if (is_a($form->getConfig()->getType()->getInnerType(), CheckboxType::class, true)) {
243 21
            $type = Types::BOOLEAN;
244
        }
245
246 21
        if (is_a($form->getConfig()->getType()->getInnerType(), IntegerType::class, true)) {
247
            $type = Types::INT;
248
        }
249
250 21
        if (is_a($form->getConfig()->getType()->getInnerType(), NumberType::class, true)) {
251
            $type = Types::FLOAT;
252
        }
253
254 21
        if (!$type) {
255
            $error = sprintf(
256
                'The field "%s" in the parent form "%s" does not have a valid type. 
257
                If your are using a custom type, must define a option called "graphql_type" to resolve the form to a valid GraphQL type',
258
                $form->getName(),
259
                $form->getParent()->getName()
260
            );
261
            throw new \InvalidArgumentException($error);
262
        }
263
264 21
        $field->setType($type);
265 21
    }
266
}
267