BuildSchema::performAction()   F
last analyzed

Complexity

Conditions 20
Paths 164

Size

Total Lines 106
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 20
eloc 71
c 1
b 0
f 0
nc 164
nop 0
dl 0
loc 106
rs 3.6333

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
4
namespace Swaggest\JsonCli;
5
6
use Swaggest\JsonCli\JsonSchema\ResolverMux;
7
use Swaggest\JsonDiff\JsonDiff;
8
use Swaggest\JsonDiff\JsonPointer;
9
use Swaggest\JsonSchema\Context;
10
use Swaggest\JsonSchema\InvalidValue;
11
use Swaggest\JsonSchema\RemoteRef\BasicFetcher;
12
use Swaggest\JsonSchema\RemoteRef\Preloaded;
13
use Swaggest\JsonSchema\Schema;
14
use Swaggest\JsonSchemaMaker\SchemaMaker;
15
use Yaoi\Command;
16
17
class BuildSchema extends Base
18
{
19
    public $schema;
20
    public $data;
21
22
    public $additionalData;
23
24
    /** @var string */
25
    public $ptrInSchema;
26
27
    /** @var string */
28
    public $ptrInData;
29
30
    public $jsonl = false;
31
32
    public $useNullable = false;
33
34
    public $useXNullable = false;
35
36
    public $collectExamples = false;
37
38
    public $defsPtr = '#/definitions/';
39
40
    public $heuristicRequired = false;
41
42
    /**
43
     * @param Command\Definition $definition
44
     * @param \stdClass|static $options
45
     */
46
    static function setUpDefinition(Command\Definition $definition, $options)
47
    {
48
        $options->data = Command\Option::create()->setIsUnnamed()->setIsRequired()
49
            ->setDescription('Path to data (JSON/YAML)');
50
        $options->schema = Command\Option::create()->setIsUnnamed()
51
            ->setDescription('Path to parent schema');
52
        $options->ptrInSchema = Command\Option::create()->setType()
0 ignored issues
show
Documentation Bug introduced by
It seems like Yaoi\Command\Option::cre...oot schema, default #') of type Yaoi\Command\Option is incompatible with the declared type string of property $ptrInSchema.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53
            ->setDescription('JSON pointer to structure in root schema, default #');
54
        $options->ptrInData = Command\Option::create()->setType()
0 ignored issues
show
Documentation Bug introduced by
It seems like Yaoi\Command\Option::cre...re in data, default #') of type Yaoi\Command\Option is incompatible with the declared type string of property $ptrInData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
55
            ->setDescription('JSON pointer to structure in data, default #');
56
        $options->jsonl = Command\Option::create()->setDescription('Data is a stream of JSON Lines');
57
58
        $options->useNullable = Command\Option::create()
59
            ->setDescription('Use `nullable: true` instead of `type: null`, OAS 3.0 compatibility');
60
61
        $options->useXNullable = Command\Option::create()
62
            ->setDescription('Use `x-nullable: true` instead of `type: null`, Swagger 2.0 compatibility');
63
64
        $options->defsPtr = Command\Option::create()->setType()
65
            ->setDescription('Location to put new definitions. default: "#/definitions/"');
66
67
        $options->collectExamples = Command\Option::create()
68
            ->setDescription('Collect scalar values example');
69
70
        $options->heuristicRequired = Command\Option::create()
71
            ->setDescription('Mark properties that are available in all samples as `required`.');
72
73
        $options->additionalData = Command\Option::create()->setType()->setIsVariadic()
74
            ->setDescription('Additional paths to data');
75
76
        parent::setUpDefinition($definition, $options);
77
    }
78
79
80
    /**
81
     * @throws ExitCode
82
     * @throws \Swaggest\JsonSchema\Exception
83
     */
84
    public function performAction()
85
    {
86
        $schema = new Schema();
87
88
        if ($this->schema) {
89
            $schemaDataOrig = $this->readData($this->schema);
90
            $schemaData = $schemaDataOrig;
91
92
            $resolver = new ResolverMux();
93
94
            if (!empty($this->ptrInSchema)) {
95
                $baseName = basename($this->schema);
96
                $preloaded = new Preloaded();
97
                $preloaded->setSchemaData($baseName, $schemaData);
98
                $resolver->resolvers[] = $preloaded;
99
                $schemaData = (object)[Schema::PROP_REF => $baseName . $this->ptrInSchema];
100
            }
101
102
            $resolver->resolvers[] = new BasicFetcher();
103
104
            try {
105
                $schemaContract = Schema::import($schemaData, new Context($resolver));
106
                if ($schemaContract instanceof Schema) {
107
                    $schema = $schemaContract;
108
                }
109
            } catch (InvalidValue $e) {
110
                $this->response->error('Invalid schema');
111
                $this->response->addContent($e->getMessage());
112
                throw new ExitCode('', 1);
113
            } catch (\Exception $e) {
114
                $this->response->error('Failed to import schema:' . $e->getMessage());
115
                throw new ExitCode('', 1);
116
            }
117
        }
118
119
        $maker = new SchemaMaker($schema);
120
        $maker->options->useXNullable = $this->useXNullable;
121
        $maker->options->useNullable = $this->useNullable;
122
        $maker->options->defsPtr = $this->defsPtr;
123
        $maker->options->collectExamples = $this->collectExamples;
124
        $maker->options->heuristicRequired = $this->heuristicRequired;
125
126
        if ($this->jsonl) {
127
            $pathInData = [];
128
            if ($this->ptrInData) {
129
                $pathInData = JsonPointer::splitPath($this->ptrInData);
130
            }
131
132
            $handle = fopen($this->data, "r");
133
            if ($handle) {
0 ignored issues
show
introduced by
$handle is of type resource, thus it always evaluated to false.
Loading history...
134
                while (($buffer = fgets($handle)) !== false) {
135
                    $item = json_decode($buffer);
136
                    // Tolerate and skip malformed JSON line.
137
                    if (null === $item) {
138
                        continue;
139
                    }
140
                    if ($this->ptrInData) {
141
                        $item = JsonPointer::get($item, $pathInData);
142
                    }
143
                    $maker->addInstanceValue($item);
144
                }
145
                if (!feof($handle)) {
146
                    echo "Error: unexpected fgets() fail\n";
147
                }
148
                fclose($handle);
149
            }
150
        } else {
151
            $data = $this->readData($this->data);
152
            $maker->addInstanceValue($data);
153
154
            if (!empty($this->additionalData)) {
155
                foreach ($this->additionalData as $path) {
156
                    $data = $this->readData($path);
157
                    $maker->addInstanceValue($data);
158
                }
159
            }
160
        }
161
162
163
        $s = Schema::export($schema);
164
        $this->out = $s;
165
166
        if ($this->ptrInSchema && isset($schemaDataOrig)) {
167
            $tmp = json_encode($schemaDataOrig);
168
            if ($tmp === false) {
169
                throw new ExitCode('Failed to encode JSON', 1);
170
            }
171
            $schemaDataResult = json_decode($tmp);
172
173
            $defs = JsonPointer::get($s, JsonPointer::splitPath(rtrim($this->defsPtr, '/')));
174
            foreach ($defs as $name => $def) {
175
                JsonPointer::add($schemaDataResult, JsonPointer::splitPath($this->defsPtr . $name), $def);
176
            }
177
            JsonPointer::remove($s, JsonPointer::splitPath(rtrim($this->defsPtr, '/')));
178
            JsonPointer::add($schemaDataResult, JsonPointer::splitPath($this->ptrInSchema), $s);
179
180
            $tmp = json_encode($schemaDataResult);
181
            if ($tmp === false) {
182
                throw new ExitCode('Failed to encode JSON', 1);
183
            }
184
            $schemaDataResult = json_decode($tmp);
185
            $diff = new JsonDiff($schemaDataOrig, $schemaDataResult, JsonDiff::REARRANGE_ARRAYS);
186
            $this->out = $diff->getRearranged();
187
        }
188
189
        $this->postPerform();
190
    }
191
}