Completed
Push — master ( 8d92e8...b6ba0d )
by Viacheslav
07:56
created

BuildSchema   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 88
c 1
b 0
f 0
dl 0
loc 145
rs 10
wmc 18

2 Methods

Rating   Name   Duplication   Size   Complexity  
A setUpDefinition() 0 22 1
D performAction() 0 93 17
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\JsonSchemaFromInstance;
15
use Yaoi\Command;
16
17
class BuildSchema extends Base
18
{
19
    public $schema;
20
    public $data;
21
22
    /** @var string */
23
    public $ptrInSchema;
24
25
    /** @var string */
26
    public $ptrInData;
27
28
    public $jsonl = false;
29
30
    public $useNullable = false;
31
32
    public $useXNullable = false;
33
34
    public $defsPtr = '#/definitions/';
35
36
    /**
37
     * @param Command\Definition $definition
38
     * @param \stdClass|static $options
39
     */
40
    static function setUpDefinition(Command\Definition $definition, $options)
41
    {
42
        $options->data = Command\Option::create()->setIsUnnamed()->setIsRequired()
43
            ->setDescription('Path to data (JSON/YAML)');
44
        $options->schema = Command\Option::create()->setIsUnnamed()
45
            ->setDescription('Path to parent schema');
46
        $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...
47
            ->setDescription('JSON pointer to structure in root schema, default #');
48
        $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...
49
            ->setDescription('JSON pointer to structure in data, default #');
50
        $options->jsonl = Command\Option::create()->setDescription('Data is a stream of JSON Lines');
51
52
        $options->useNullable = Command\Option::create()
53
            ->setDescription('Use `nullable: true` instead of `type: null`, OAS 3.0 compatibility');
54
55
        $options->useXNullable = Command\Option::create()
56
            ->setDescription('Use `x-nullable: true` instead of `type: null`, Swagger 2.0 compatibility');
57
58
        $options->defsPtr = Command\Option::create()->setType()
59
            ->setDescription('Location to put new definitions. default: "#/definitions/"');
60
61
        parent::setUpDefinition($definition, $options);
62
    }
63
64
65
    /**
66
     * @throws ExitCode
67
     * @throws \Swaggest\JsonSchema\Exception
68
     */
69
    public function performAction()
70
    {
71
        $schema = new Schema();
72
73
        if ($this->schema) {
74
            $schemaDataOrig = $this->readData($this->schema);
75
            $schemaData = $schemaDataOrig;
76
77
            $resolver = new ResolverMux();
78
79
            if (!empty($this->ptrInSchema)) {
80
                $baseName = basename($this->schema);
81
                $preloaded = new Preloaded();
82
                $preloaded->setSchemaData($baseName, $schemaData);
83
                $resolver->resolvers[] = $preloaded;
84
                $schemaData = (object)[Schema::PROP_REF => $baseName . $this->ptrInSchema];
85
            }
86
87
            $resolver->resolvers[] = new BasicFetcher();
88
89
            try {
90
                $schemaContract = Schema::import($schemaData, new Context($resolver));
91
                if ($schemaContract instanceof Schema) {
92
                    $schema = $schemaContract;
93
                }
94
            } catch (InvalidValue $e) {
95
                $this->response->error('Invalid schema');
96
                $this->response->addContent($e->getMessage());
97
                throw new ExitCode('', 1);
98
            } catch (\Exception $e) {
99
                $this->response->error('Failed to import schema:' . $e->getMessage());
100
                throw new ExitCode('', 1);
101
            }
102
        }
103
104
        $maker = new JsonSchemaFromInstance($schema);
105
        $maker->options->useXNullable = $this->useXNullable;
106
        $maker->options->useNullable = $this->useNullable;
107
        $maker->options->defsPtr = $this->defsPtr;
108
109
        if ($this->jsonl) {
110
            $pathInData = [];
111
            if ($this->ptrInData) {
112
                $pathInData = JsonPointer::splitPath($this->ptrInData);
113
            }
114
115
            $handle = fopen($this->data, "r");
116
            if ($handle) {
0 ignored issues
show
introduced by
$handle is of type false|resource, thus it always evaluated to false.
Loading history...
117
                while (($buffer = fgets($handle)) !== false) {
118
                    $item = json_decode($buffer);
119
                    if ($this->ptrInData) {
120
                        $item = JsonPointer::get($item, $pathInData);
121
                    }
122
                    $maker->addInstanceValue($item);
123
                }
124
                if (!feof($handle)) {
125
                    echo "Error: unexpected fgets() fail\n";
126
                }
127
                fclose($handle);
128
            }
129
        } else {
130
            $data = $this->readData($this->data);
131
            $maker->addInstanceValue($data);
132
        }
133
134
135
        $s = Schema::export($schema);
136
        $this->out = $s;
137
138
        if ($this->ptrInSchema && isset($schemaDataOrig)) {
139
            $tmp = json_encode($schemaDataOrig);
140
            if ($tmp === false) {
141
                throw new ExitCode('Failed to encode JSON', 1);
142
            }
143
            $schemaDataResult = json_decode($tmp);
144
145
            $defs = JsonPointer::get($s, JsonPointer::splitPath(rtrim($this->defsPtr, '/')));
146
            foreach ($defs as $name => $def) {
147
                JsonPointer::add($schemaDataResult, JsonPointer::splitPath($this->defsPtr . $name), $def);
148
            }
149
            JsonPointer::remove($s, JsonPointer::splitPath(rtrim($this->defsPtr, '/')));
150
            JsonPointer::add($schemaDataResult, JsonPointer::splitPath($this->ptrInSchema), $s);
151
152
            $tmp = json_encode($schemaDataResult);
153
            if ($tmp === false) {
154
                throw new ExitCode('Failed to encode JSON', 1);
155
            }
156
            $schemaDataResult = json_decode($tmp);
157
            $diff = new JsonDiff($schemaDataOrig, $schemaDataResult, JsonDiff::REARRANGE_ARRAYS);
158
            $this->out = $diff->getRearranged();
159
        }
160
161
        $this->postPerform();
162
    }
163
}