Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Pull Request — master (#461)
by
unknown
21:27
created

FormDescriber::isNumbersArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
/*
3
 * This file is part of the NelmioApiDocBundle package.
4
 *
5
 * (c) Nelmio
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace Overblog\GraphQLBundle\Definition\Builder;
11
12
use GraphQL\Type\Definition\Type as GraphQLType;
13
14
use Nelmio\ApiDocBundle\Model\Model;
0 ignored issues
show
Bug introduced by
The type Nelmio\ApiDocBundle\Model\Model was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Symfony\Component\Form\AbstractType;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\AbstractType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Symfony\Component\Form\Extension\Core\Type\FormType;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\E...sion\Core\Type\FormType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Symfony\Component\Form\FormConfigBuilderInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\FormConfigBuilderInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Symfony\Component\Form\FormFactoryInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\FormFactoryInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Symfony\Component\Form\FormInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\FormInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Symfony\Component\Form\FormTypeInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\FormTypeInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Symfony\Component\Form\ResolvedFormTypeInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Form\ResolvedFormTypeInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use Symfony\Component\PropertyInfo\Type;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\PropertyInfo\Type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
/**
24
 * @internal
25
 */
26
final class FormDescriber
27
{
28
    
29
    const SIMPLE_TYPES = [
30
        'text'=>'string',
31
        'number'=>'float',
32
        'integer'=>'int',
33
        'date'=>'string',
34
        'datetime'=>'string',
35
        'password'=>'string',
36
        'checkbox'=>'boolean',
37
    ];
38
    
39
    private $formFactory;
40
    public function __construct(FormFactoryInterface $formFactory = null)
41
    {
42
        $this->formFactory = $formFactory;
43
    }
44
    public function describe($class)
45
    {
46
        if (method_exists(AbstractType::class, 'setDefaultOptions')) {
47
            throw new \LogicException('symfony/form < 3.0 is not supported, please upgrade to an higher version to use a form as a model.');
48
        }
49
        if (null === $this->formFactory) {
50
            throw new \LogicException('You need to enable forms in your application to use a form as a model.');
51
        }
52
        $form = $this->formFactory->create($class, null, []);
53
        return $this->parseForm($form);
54
    }
55
56
    private function parseForm(FormInterface $form)
57
    {
58
        $fields = [];
59
        foreach ($form as $name => $child) {
60
            $config = $child->getConfig();
61
            $required = $config->getRequired();
62
            $field = [
63
                'name'=>$name,
64
                'type'=>$this->getType($config, $required),
65
                
66
            ];
67
            $fields[] = $field;
68
        }
69
        
70
        return $fields;
71
    }
72
    
73
    private function getType(FormConfigBuilderInterface $config, $required)
74
    {
75
        $type = $config->getType();
76
        
77
        if (!$builtinFormType = $this->getBuiltinFormType($type)) {
78
            // if form type is not builtin in Form component.
79
            $type = get_class($type->getInnerType());
80
            //TODO : Create nested type
81
            return $type;
82
        }
83
        
84
        $blockPrefix = $builtinFormType->getBlockPrefix();
85
        if(in_array($blockPrefix, array_keys(self::SIMPLE_TYPES))) {
86
            $typeName = self::SIMPLE_TYPES[$blockPrefix];
87
            $type = GraphQLType::{$typeName}();
88
89
            return $required ? GraphQLType::nonNull($type) : $type;
90
        }
91
        
92
        if ('choice' === $blockPrefix) {
93
            $multiple = $config->getOption('multiple');
94
            if (($choices = $config->getOption('choices')) && is_array($choices) && count($choices)) {
95
                $enums = array_values($choices);
96
                if ($this->isNumbersArray($enums)) {
97
                    $type = 'number';
0 ignored issues
show
Unused Code introduced by
The assignment to $type is dead and can be removed.
Loading history...
98
                } elseif ($this->isBooleansArray($enums)) {
99
                    $type = 'boolean';
100
                } else {
101
                    $type = 'string';
102
                } 
103
                $enumName = $this->createEnum($config->getName(), $enums);
0 ignored issues
show
Bug introduced by
The method createEnum() does not exist on Overblog\GraphQLBundle\D...n\Builder\FormDescriber. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

103
                /** @scrutinizer ignore-call */ 
104
                $enumName = $this->createEnum($config->getName(), $enums);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
104
                if ($multiple) {
105
                    return sprintf("[%s]%s", $enumName, $required?"!":"");
106
                }
107
                return sprintf("[%s]%s", $enumName, $required?"!":"");
108
            }
109
            if ($multiple) {
110
                return sprintf("[String]%s", $required?"!":"");
111
            }
112
            return sprintf("String%s", $required?"!":"");
113
        }
114
115
        if ('repeated' === $blockPrefix) {
116
            $property->setType('object');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $property seems to be never defined.
Loading history...
117
            $property->setRequired([$config->getOption('first_name'), $config->getOption('second_name')]);
118
            $subType = $config->getOption('type');
119
            foreach (['first', 'second'] as $subField) {
120
                $subName = $config->getOption($subField.'_name');
121
                $subForm = $this->formFactory->create($subType, null, array_merge($config->getOption('options'), $config->getOption($subField.'_options')));
0 ignored issues
show
Bug introduced by
The method create() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

121
                /** @scrutinizer ignore-call */ 
122
                $subForm = $this->formFactory->create($subType, null, array_merge($config->getOption('options'), $config->getOption($subField.'_options')));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
122
                $this->findFormType($subForm->getConfig(), $property->getProperties()->get($subName));
123
            }
124
        }
125
        if ('collection' === $blockPrefix) {
126
            $subType = $config->getOption('entry_type');
127
            $subOptions = $config->getOption('entry_options');
128
            $subForm = $this->formFactory->create($subType, null, $subOptions);
129
            $property->setType('array');
130
            $itemsProp = $property->getItems();
131
            $this->findFormType($subForm->getConfig(), $itemsProp);
132
            //break;
133
        }
134
        // The DocumentType is bundled with the DoctrineMongoDBBundle
135
        if ('entity' === $blockPrefix || 'document' === $blockPrefix) {
136
            $entityClass = $config->getOption('class');
137
            if ($config->getOption('multiple')) {
138
                $property->setFormat(sprintf('[%s id]', $entityClass));
139
                $property->setType('array');
140
                $property->getItems()->setType('string');
141
            } else {
142
                $property->setType('string');
143
                $property->setFormat(sprintf('%s id', $entityClass));
144
            }
145
            //break;
146
        }
147
    }
148
149
    /**
150
     * Finds and sets the schema type on $property based on $config info.
151
     *
152
     * Returns true if a native Swagger type was found, false otherwise
153
     *
154
     * @param FormConfigBuilderInterface $config
155
     * @param                            $property
156
     */
157
    private function findFormType(FormConfigBuilderInterface $config, $property)
158
    {
159
        $type = $config->getType();
160
        if (!$builtinFormType = $this->getBuiltinFormType($type)) {
161
            // if form type is not builtin in Form component.
162
            $model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, get_class($type->getInnerType())));
163
            $property->setRef($this->modelRegistry->register($model));
0 ignored issues
show
Bug Best Practice introduced by
The property modelRegistry does not exist on Overblog\GraphQLBundle\D...n\Builder\FormDescriber. Did you maybe forget to declare it?
Loading history...
164
            return;
165
        }
166
        do {
167
            $blockPrefix = $builtinFormType->getBlockPrefix();
168
            if ('text' === $blockPrefix) {
169
                $property->setType('string');
170
                break;
171
            }
172
            if ('number' === $blockPrefix) {
173
                $property->setType('number');
174
                break;
175
            }
176
            if ('integer' === $blockPrefix) {
177
                $property->setType('integer');
178
                break;
179
            }
180
            if ('date' === $blockPrefix) {
181
                $property->setType('string');
182
                $property->setFormat('date');
183
                break;
184
            }
185
            if ('datetime' === $blockPrefix) {
186
                $property->setType('string');
187
                $property->setFormat('date-time');
188
                break;
189
            }
190
            if ('choice' === $blockPrefix) {
191
                if ($config->getOption('multiple')) {
192
                    $property->setType('array');
193
                } else {
194
                    $property->setType('string');
195
                }
196
                if (($choices = $config->getOption('choices')) && is_array($choices) && count($choices)) {
197
                    $enums = array_values($choices);
198
                    if ($this->isNumbersArray($enums)) {
199
                        $type = 'number';
200
                    } elseif ($this->isBooleansArray($enums)) {
201
                        $type = 'boolean';
202
                    } else {
203
                        $type = 'string';
204
                    }
205
                    if ($config->getOption('multiple')) {
206
                        $property->getItems()->setType($type)->setEnum($enums);
207
                    } else {
208
                        $property->setType($type)->setEnum($enums);
209
                    }
210
                }
211
                break;
212
            }
213
            if ('checkbox' === $blockPrefix) {
214
                $property->setType('boolean');
215
                break;
216
            }
217
            if ('password' === $blockPrefix) {
218
                $property->setType('string');
219
                $property->setFormat('password');
220
                break;
221
            }
222
            if ('repeated' === $blockPrefix) {
223
                $property->setType('object');
224
                $property->setRequired([$config->getOption('first_name'), $config->getOption('second_name')]);
225
                $subType = $config->getOption('type');
226
                foreach (['first', 'second'] as $subField) {
227
                    $subName = $config->getOption($subField.'_name');
228
                    $subForm = $this->formFactory->create($subType, null, array_merge($config->getOption('options'), $config->getOption($subField.'_options')));
229
                    $this->findFormType($subForm->getConfig(), $property->getProperties()->get($subName));
230
                }
231
                break;
232
            }
233
            if ('collection' === $blockPrefix) {
234
                $subType = $config->getOption('entry_type');
235
                $subOptions = $config->getOption('entry_options');
236
                $subForm = $this->formFactory->create($subType, null, $subOptions);
237
                $property->setType('array');
238
                $itemsProp = $property->getItems();
239
                $this->findFormType($subForm->getConfig(), $itemsProp);
240
                break;
241
            }
242
            // The DocumentType is bundled with the DoctrineMongoDBBundle
243
            if ('entity' === $blockPrefix || 'document' === $blockPrefix) {
244
                $entityClass = $config->getOption('class');
245
                if ($config->getOption('multiple')) {
246
                    $property->setFormat(sprintf('[%s id]', $entityClass));
247
                    $property->setType('array');
248
                    $property->getItems()->setType('string');
249
                } else {
250
                    $property->setType('string');
251
                    $property->setFormat(sprintf('%s id', $entityClass));
252
                }
253
                break;
254
            }
255
        } while ($builtinFormType = $builtinFormType->getParent());
256
    }
257
    /**
258
     * @param array $array
259
     *
260
     * @return bool true if $array contains only numbers, false otherwise
261
     */
262
    private function isNumbersArray(array $array): bool
263
    {
264
        foreach ($array as $item) {
265
            if (!is_numeric($item)) {
266
                return false;
267
            }
268
        }
269
        return true;
270
    }
271
    /**
272
     * @param array $array
273
     *
274
     * @return bool true if $array contains only booleans, false otherwise
275
     */
276
    private function isBooleansArray(array $array): bool
277
    {
278
        foreach ($array as $item) {
279
            if (!is_bool($item)) {
280
                return false;
281
            }
282
        }
283
        return true;
284
    }
285
    /**
286
     * @param ResolvedFormTypeInterface $type
287
     *
288
     * @return ResolvedFormTypeInterface|null
289
     */
290
    private function getBuiltinFormType(ResolvedFormTypeInterface $type)
291
    {
292
        do {
293
            $class = get_class($type->getInnerType());
294
            if (FormType::class === $class) {
295
                return null;
296
            }
297
            if ('entity' === $type->getBlockPrefix() || 'document' === $type->getBlockPrefix()) {
298
                return $type;
299
            }
300
            if (0 === strpos($class, 'Symfony\Component\Form\Extension\Core\Type\\')) {
301
                return $type;
302
            }
303
        } while ($type = $type->getParent());
304
        return null;
305
    }
306
}