Passed
Push — master ( c39fb6...9e9a0d )
by Rafael
04:42
created

resolveFormFieldDefinition()   F

Complexity

Conditions 11
Paths 384

Size

Total Lines 46
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 13.3605

Importance

Changes 0
Metric Value
cc 11
eloc 26
nc 384
nop 2
dl 0
loc 46
ccs 19
cts 26
cp 0.7308
crap 13.3605
rs 3.8181
c 0
b 0
f 0

How to fix   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 GraphQL\Type\Definition\Type;
14
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
15
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
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\TextType;
19
use Symfony\Component\Form\FormFactory;
20
use Symfony\Component\Form\FormInterface;
21
use Ynlo\GraphQLBundle\Definition\ArgumentDefinition;
22
use Ynlo\GraphQLBundle\Definition\DefinitionInterface;
23
use Ynlo\GraphQLBundle\Definition\FieldDefinition;
24
use Ynlo\GraphQLBundle\Definition\InputObjectDefinition;
25
use Ynlo\GraphQLBundle\Definition\MutationDefinition;
26
use Ynlo\GraphQLBundle\Definition\NodeAwareDefinitionInterface;
27
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
28
use Ynlo\GraphQLBundle\Form\Type\GraphQLType;
29
use Ynlo\GraphQLBundle\Form\Type\IDType;
30
use Ynlo\GraphQLBundle\Util\ClassUtils;
31
32
/**
33
 * MutationFormResolverExtension
34
 */
35
class MutationFormResolverExtension extends AbstractDefinitionExtension
36
{
37
    /**
38
     * @var FormFactory
39
     */
40
    protected $formFactory;
41
42
    /**
43
     * @param FormFactory $formFactory
44
     */
45 1
    public function __construct(FormFactory $formFactory)
46
    {
47 1
        $this->formFactory = $formFactory;
48 1
    }
49
50
    /**
51
     * {@inheritDoc}
52
     */
53 1
    public function getName(): string
54
    {
55 1
        return 'form';
56
    }
57
58
    /**
59
     * {@inheritDoc}
60
     */
61 1
    public function buildConfig(ArrayNodeDefinition $root)
62
    {
63
        $config = $root
64 1
            ->info('Resolve the form to use as input for mutations')
65 1
            ->addDefaultsIfNotSet()
66 1
            ->canBeDisabled()
67 1
            ->children();
68
69 1
        $config->variableNode('type')
70 1
               ->defaultNull()
71 1
               ->info(
72 1
                   'Specify the form type to use,
73
[string] Name of the form type to use
74
[true|null] The form will be automatically resolved to ...Bundle\Form\Input\{Node}\{MutationName}Input.
75
[true] Throw a exception if the form can`t be located
76
[false] The form is not required and should not be resolved'
77
               );
78 1
        $config->variableNode('options')->defaultValue([])->info('Form options');
79 1
        $config->variableNode('argument')
80 1
               ->defaultValue('input')
81 1
               ->info('Name of the argument to use as input');
82
83 1
        $config->booleanNode('client_mutation_id')
84 1
               ->defaultTrue()
85 1
               ->info('Automatically add a field called clientMutationId');
86 1
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91 1
    public function configure(DefinitionInterface $definition, Endpoint $endpoint, array $config)
92
    {
93 1
        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...
94 1
            return;
95
        }
96
97 1
        $formType = $config['type'] ?? null;
98
99
        //the related class is used to match a form using naming conventions
100 1
        $relatedClass = null;
101 1
        if ($definition instanceof NodeAwareDefinitionInterface && $definition->getNode()) {
102 1
            $relatedClass = $definition->getNode();
103 1
            if ($class = $endpoint->getClassForType($relatedClass)) {
104 1
                $relatedClass = $class;
105
            }
106
        } elseif ($definition->getResolver()) {
107
            $relatedClass = $definition->getResolver();
108
        }
109
110
        //try find the form using a related class
111 1
        if ($relatedClass && (!$formType || true === $formType)) {
112 1
            $bundleNamespace = ClassUtils::relatedBundleNamespace($relatedClass);
113 1
            $formClass = ClassUtils::applyNamingConvention(
114 1
                $bundleNamespace,
115 1
                'Form\Input',
116 1
                $definition->getNode(),
117 1
                ucfirst($definition->getName()),
118 1
                'Input'
119
            );
120 1
            if (class_exists($formClass)) {
121 1
                $formType = $formClass;
122
            } elseif (true === $formType) {
123
                $error = sprintf(
124
                    'Can`t find a valid input form type to use in "%s".
125
                         Create the form "%s" or specify a custom form',
126
                    $definition->getName(),
127
                    $formClass
128
                );
129
                throw new \Exception($error);
130
            }
131
        }
132
133 1
        if ($formType) {
134 1
            $config['type'] = $formType;
135
136 1
            $form = $this->formFactory->create($formType, null, $config['options'] ?? []);
137 1
            $inputObject = $this->createFormInputObject($endpoint, $form, ucfirst($definition->getName()));
138 1
            $endpoint->addType($inputObject);
139
140 1
            $input = new ArgumentDefinition();
141 1
            $input->setName($config['argument']);
142 1
            $input->setType($inputObject->getName());
143
144 1
            if ($config['client_mutation_id']) {
145 1
                $clientMutationId = new FieldDefinition();
146 1
                $clientMutationId->setName('clientMutationId');
147 1
                $clientMutationId->setType(Type::STRING);
148 1
                $clientMutationId->setDescription('A unique identifier for the client performing the mutation.');
149 1
                $inputObject->prependField($clientMutationId);
150
            }
151
152 1
            $definition->addArgument($input);
153 1
            $definition->setMeta('form', $config);
154
        }
155 1
    }
156
157
    /**
158
     * @param Endpoint      $endpoint
159
     * @param FormInterface $form
160
     * @param string        $name
161
     *
162
     * @return InputObjectDefinition
163
     */
164 1
    public function createFormInputObject(Endpoint $endpoint, FormInterface $form, $name)
165
    {
166 1
        $inputObject = new InputObjectDefinition();
167 1
        $inputObject->setName($name.'Input');
168
169 1
        foreach ($form->all() as $formField) {
170 1
            $field = new FieldDefinition();
171 1
            $field->setName($formField->getConfig()->getOption('label') ?? $formField->getName());
172 1
            $field->setNonNull($formField->isRequired());
173 1
            $field->setOriginName($formField->getName());
174
175 1
            if ($formField->all()) {
176 1
                $childName = $name.ucfirst($formField->getName());
177 1
                $child = $this->createFormInputObject($endpoint, $formField, $childName);
178 1
                $endpoint->addType($child);
179 1
                $field->setType($child->getName());
180
            } else {
181 1
                $this->resolveFormFieldDefinition($field, $formField);
182
            }
183
184 1
            $inputObject->addField($field);
185
        }
186
187 1
        return $inputObject;
188
    }
189
190
    /**
191
     * @param FieldDefinition $field
192
     * @param FormInterface   $form
193
     */
194 1
    public function resolveFormFieldDefinition(FieldDefinition $field, FormInterface $form)
195
    {
196 1
        $type = null;
197 1
        $resolver = $form->getConfig()->getType()->getOptionsResolver();
198 1
        if ($resolver->hasDefault('graphql_type')) {
199
            $type = $resolver->resolve([])['graphql_type'];
200
        }
201
202 1
        if (is_a($form->getConfig()->getType()->getInnerType(), GraphQLType::class, true)) {
203 1
            $type = $form->getConfig()->getOptions()['graphql_type'];
204
        }
205
206 1
        if (is_a($form->getConfig()->getType()->getInnerType(), IDType::class, true)) {
207 1
            if ($form->getConfig()->hasOption('multiple') && $form->getConfig()->getOption('multiple')) {
208 1
                $field->setList(true);
209
            }
210 1
            $type = Type::ID;
211
        }
212
213 1
        if (is_a($form->getConfig()->getType()->getInnerType(), TextType::class, true)) {
214 1
            $type = Type::STRING;
215
        }
216
217 1
        if (is_a($form->getConfig()->getType()->getInnerType(), EmailType::class, true)) {
218 1
            $type = Type::STRING;
219
        }
220
221 1
        if (is_a($form->getConfig()->getType()->getInnerType(), CheckboxType::class, true)) {
222 1
            $type = Type::BOOLEAN;
223
        }
224
225 1
        if (is_a($form->getConfig()->getType()->getInnerType(), IntegerType::class, true)) {
226
            $type = Type::INT;
227
        }
228
229 1
        if (!$type) {
230
            $error = sprintf(
231
                'The field "%s" in the parent form "%s" does not have a valid type. 
232
                If your are using a custom type, must define a option called "graphql_type" to resolve the form to a valid GraphQL type',
233
                $form->getName(),
234
                $form->getParent()->getName()
235
            );
236
            throw new \InvalidArgumentException($error);
237
        }
238
239 1
        $field->setType($type);
240 1
    }
241
}
242