Completed
Pull Request — master (#43)
by Jose Manuel
02:54
created

GenerateConfig::checkArguments()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 0
cts 9
cp 0
rs 9.8666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
namespace Softonic\GraphQL\Console\Mutation;
4
5
use Softonic\GraphQL\Config\MutationTypeConfig;
6
use Softonic\GraphQL\DataObjects\Mutation\Collection;
7
use Softonic\GraphQL\DataObjects\Mutation\Item;
8
use stdClass;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
class GenerateConfig extends Command
15
{
16
    const SCALAR = 'SCALAR';
17
18
    const INPUT_OBJECT = 'INPUT_OBJECT';
19
20
    const LIST = 'LIST';
21
22
    protected static $defaultName = 'mutation:generate-config';
23
24
    protected function configure()
25
    {
26
        $this->setDescription('Creates a mutation config.')
27
            ->setHelp('This command allows you to create a mutation config based in the result of a ' .
28
                'introspection query for a specific mutation.');
29
30
        $this
31
            ->addArgument(
32
                'instrospection-result',
33
                InputArgument::REQUIRED,
34
                'Json file with the introspection query result'
35
            )
36
            ->addArgument(
37
                'mutation',
38
                InputArgument::REQUIRED,
39
                'Mutation name to extract to the configuration'
40
            );
41
    }
42
43
    protected function execute(InputInterface $input, OutputInterface $output)
44
    {
45
        if (!$this->checkArguments($input, $output)) {
46
            return 1;
47
        }
48
49
        $jsonSchema = file_get_contents($input->getArgument('instrospection-result'));
50
        $mutation   = $input->getArgument('mutation');
51
52
        $mutationConfig = $this->generateConfig(json_decode($jsonSchema), $mutation);
0 ignored issues
show
Bug introduced by
It seems like $mutation defined by $input->getArgument('mutation') on line 50 can also be of type array<integer,string> or null; however, Softonic\GraphQL\Console...onfig::generateConfig() does only seem to accept string, 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...
53
54
        $output->writeln(var_export($mutationConfig, true));
55
56
        return 0;
57
    }
58
59
    private function checkArguments(InputInterface $input, OutputInterface $output)
60
    {
61
        $jsonPath = $input->getArgument('instrospection-result');
62
63
        if (!file_exists($jsonPath)) {
64
            $output->writeln("The file '{$jsonPath}' does not exist");
65
66
            return false;
67
        }
68
69
        return true;
70
    }
71
72
    private function generateConfig(StdClass $jsonSchema, string $mutation)
73
    {
74
        foreach ($jsonSchema->data->__schema->types as $type) {
75
            if ($type->name === 'Mutation' && $type->fields[0]->name === $mutation) {
76
                $initialMutationField = $type->fields[0]->args[0]->name;
77
                $inputType            = $type->fields[0]->args[0]->type->ofType->name;
78
                break;
79
            }
80
        }
81
82
        return [
83
            $mutation => [
84
                $initialMutationField => [
0 ignored issues
show
Bug introduced by
The variable $initialMutationField does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
85
                    'linksTo'  => '.',
86
                    'type'     => Item::class,
87
                    'children' => $this->getMutationConfig($jsonSchema, $inputType),
0 ignored issues
show
Bug introduced by
The variable $inputType does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
88
                ],
89
            ],
90
        ];
91
    }
92
93
    private function getTypeFromField($field)
94
    {
95
        $isCollection = false;
96
        $type         = $field->type;
97
98
        while ($type->kind !== self::SCALAR && $type->kind !== self::INPUT_OBJECT) {
99
            if ($type->kind === self::LIST) {
100
                $isCollection = true;
101
            }
102
            $type = $type->ofType;
103
        }
104
105
        if ($type->kind === self::SCALAR) {
106
            return [
107
                'type'         => $type->kind,
108
                'isCollection' => $isCollection,
109
            ];
110
        }
111
112
        return [
113
            'type'         => $type->name,
114
            'isCollection' => $isCollection,
115
        ];
116
    }
117
118
    private function getMutationConfig(stdClass $jsonSchema, $inputType, $parentLinksTo = ''): array
119
    {
120
        $children = [];
121
        foreach ($jsonSchema->data->__schema->types as $type) {
122
            if ($type->name === $inputType) {
123
                foreach ($type->inputFields as $inputField) {
124
                    [
125
                        'type'         => $type,
126
                        'isCollection' => $isCollection,
0 ignored issues
show
Bug introduced by
The variable $isCollection does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
127
                    ] = $this->getTypeFromField($inputField);
128
129
                    if ($type === self::SCALAR) {
130
                        $children[$inputField->name] = [
131
                            'type' => MutationTypeConfig::SCALAR_DATA_TYPE,
132
                        ];
133
                        continue;
134
                    }
135
136
                    $linksTo                     = "{$parentLinksTo}.{$inputField->name}";
137
                    $children[$inputField->name] = [
138
                        'linksTo'  => $linksTo,
139
                        'type'     => $isCollection ? Collection::class : Item::class,
140
                        'children' => $this->getMutationConfig($jsonSchema, $type, $linksTo),
141
                    ];
142
                }
143
                break;
144
            }
145
        }
146
147
        return $children;
148
    }
149
}
150