Completed
Push — master ( e148c5...0b9e42 )
by Adrien
02:15
created

InputFieldsConfigurationFactory::completeField()   D

Complexity

Conditions 9
Paths 64

Size

Total Lines 39
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 22
cts 22
cp 1
rs 4.909
c 0
b 0
f 0
cc 9
eloc 21
nc 64
nop 3
crap 9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Doctrine\Factory;
6
7
use GraphQL\Doctrine\Annotation\Input;
8
use GraphQL\Doctrine\DocBlockReader;
9
use GraphQL\Type\Definition\Type;
10
use ReflectionMethod;
11
use ReflectionParameter;
12
13
/**
14
 * A factory to create a configuration for all setters of an entity
15
 */
16
class InputFieldsConfigurationFactory extends AbstractFieldsConfigurationFactory
17
{
18 4
    protected function getMethodPattern(): string
19
    {
20 4
        return '~^set[A-Z]~';
21
    }
22
23
    /**
24
     * Get the entire configuration for a method
25
     *
26
     * @param ReflectionMethod $method
27
     *
28
     * @return null|array
29
     */
30 4
    protected function methodToConfiguration(ReflectionMethod $method): ?array
31
    {
32
        // Silently ignore setter with anything than exactly 1 parameter
33 4
        $params = $method->getParameters();
34 4
        if (count($params) !== 1) {
35 2
            return null;
36
        }
37 4
        $param = reset($params);
38
39
        // Get a field from annotation, or an empty one
40 4
        $field = $this->getAnnotationReader()->getMethodAnnotation($method, Input::class) ?? new Input();
41
42 4
        if (!$field->type instanceof Type) {
43 4
            $this->convertTypeDeclarationsToInstances($method, $field);
44 4
            $this->completeField($method, $param, $field);
45
        }
46
47 3
        return $field->toArray();
48
    }
49
50
    /**
51
     * All its types will be converted from string to real instance of Type
52
     *
53
     * @param ReflectionMethod $method
54
     * @param Input $field
55
     */
56 4
    private function convertTypeDeclarationsToInstances(ReflectionMethod $method, Input $field): void
57
    {
58 4
        $field->type = $this->getTypeFromPhpDeclaration($method, $field->type);
59 4
    }
60
61
    /**
62
     * Complete field with info from doc blocks and type hints
63
     *
64
     * @param ReflectionMethod $method
65
     * @param ReflectionParameter $param
66
     * @param Input $field
67
     */
68 4
    private function completeField(ReflectionMethod $method, ReflectionParameter $param, Input $field): void
69
    {
70 4
        $fieldName = lcfirst(preg_replace('~^set~', '', $method->getName()));
71 4
        if (!$field->name) {
72 4
            $field->name = $fieldName;
73
        }
74
75 4
        $docBlock = new DocBlockReader($method);
76 4
        if (!$field->description) {
77 4
            $field->description = $docBlock->getMethodDescription();
78
        }
79
80 4
        if (!isset($field->defaultValue) && $param->isDefaultValueAvailable()) {
81 3
            $field->defaultValue = $param->getDefaultValue();
82
        }
83
84 4
        if (!isset($field->defaultValue)) {
85 4
            $field->defaultValue = $this->getPropertyDefaultValue($fieldName);
86
        }
87
88
        // If still no type, look for docblock
89 4
        if (!$field->type) {
90 4
            $typeDeclaration = $docBlock->getParameterType($param);
91 4
            $this->throwIfArray($param, $typeDeclaration);
92 4
            $field->type = $this->getTypeFromPhpDeclaration($method, $typeDeclaration, true);
93
        }
94
95
        // If still no type, look for type hint
96 4
        $type = $param->getType();
97 4
        if (!$field->type && $type) {
98 3
            $this->throwIfArray($param, (string) $type);
99 3
            $field->type = $this->reflectionTypeToType($type, true);
100
        }
101
102 4
        $field->type = $this->nonNullIfHasDefault($field->type, $field->defaultValue);
0 ignored issues
show
Bug introduced by
It seems like $field->type can also be of type null or string; however, GraphQL\Doctrine\Factory...::nonNullIfHasDefault() does only seem to accept object<GraphQL\Type\Definition\Type>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
103
104
        // If still no type, cannot continue
105 4
        $this->throwIfNotInputType($param, $field->type, 'Input');
106 3
    }
107
}
108