Completed
Push — master ( 290ae2...8ff748 )
by Viacheslav
14:11 queued 06:38
created

Base::loadSchema()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 41
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 28
nc 6
nop 2
dl 0
loc 41
ccs 0
cts 0
cp 0
crap 72
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
namespace Swaggest\JsonCli;
4
5
use Swaggest\JsonCli\JsonSchema\ResolverMux;
6
use Swaggest\JsonDiff\Exception;
7
use Swaggest\JsonDiff\JsonMergePatch;
8
use Swaggest\JsonDiff\JsonPatch;
9
use Swaggest\JsonSchema\Context;
10
use Swaggest\JsonSchema\RemoteRef\BasicFetcher;
11
use Swaggest\JsonSchema\RemoteRef\Preloaded;
12
use Swaggest\JsonSchema\Schema;
13
use Symfony\Component\Yaml\Yaml;
14
use Yaoi\Command;
15
use Yaoi\Io\Response;
16
17
abstract class Base extends Command
18
{
19 1
    public $pretty;
20
    public $toYaml;
21 1
    public $toSerialized;
22 1
    public $output;
23 1
24 1
    /**
25 1
     * @param Command\Definition $definition
26 1
     * @param \stdClass|static $options
27 1
     */
28
    static function setUpDefinition(Command\Definition $definition, $options)
29
    {
30
        $options->pretty = Command\Option::create()
31
            ->setDescription('Pretty-print result JSON');
32 6
        $options->output = Command\Option::create()->setType()
33
            ->setDescription('Path to output result, default STDOUT');
34 6
        $options->toYaml = Command\Option::create()->setDescription('Output in YAML format');
35
        $options->toSerialized = Command\Option::create()->setDescription('Output in PHP serialized format');
36
    }
37
38 6
39 6
    protected $out;
40
41
    protected function readData($path)
42
    {
43 6
        return self::readJsonOrYaml($path, $this->response);
44
    }
45 6
46
    /**
47
     * @param string $path
48 6
     * @param Response $response
49
     * @return mixed
50
     * @throws ExitCode
51 6
     */
52
    public static function readJsonOrYaml($path, $response)
53
    {
54 8
        $fileData = file_get_contents($path);
55
        if (!$fileData) {
56 8
            $response->error('Unable to read ' . $path);
57 8
            throw new ExitCode('', 1);
58 5
        }
59
        if (substr($path, -5) === '.yaml' || substr($path, -4) === '.yml') {
60
            $jsonData = Yaml::parse($fileData, Yaml::PARSE_OBJECT + Yaml::PARSE_OBJECT_FOR_MAP);
61 8
        } elseif (substr($path, -11) === '.serialized') {
62
            $jsonData = unserialize($fileData);
63 8
        } else {
64
            $jsonData = json_decode($fileData);
65
        }
66 8
67
        return $jsonData;
68
    }
69 8
70
71
    protected function postPerform()
72 8
    {
73
        $options = JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE;
74 8
        if ($this->pretty) {
75
            $options += JSON_PRETTY_PRINT;
76
        }
77
78
        if ($this->toYaml) {
79
            $result = Yaml::dump($this->out, 2, 2, Yaml::DUMP_OBJECT_AS_MAP);
80
        } elseif ($this->toSerialized) {
81
            $result = serialize($this->out);
82
        } else {
83
            $result = json_encode($this->out, $options);
84
        }
85
86
        if ($this->output) {
87
            file_put_contents($this->output, $result);
88
        } else {
89
            echo $result;
90
        }
91
    }
92
93
94
    /** @var string */
95
    public $schema;
96
    /** @var string[] */
97
    public $defPtr = ['#/definitions'];
98
    /** @var string[] */
99
    public $ptrInSchema;
100
    /** @var string[] */
101
    public $patches = [];
102
103
    /**
104
     * @param Command\Definition $definition
105
     * @param static|mixed $options
106
     */
107
    protected static function setupGenOptions(Command\Definition $definition, $options)
0 ignored issues
show
Unused Code introduced by
The parameter $definition is not used and could be removed. ( Ignorable by Annotation )

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

107
    protected static function setupGenOptions(/** @scrutinizer ignore-unused */ Command\Definition $definition, $options)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
108
    {
109
        $options->schema = Command\Option::create()
0 ignored issues
show
Documentation Bug introduced by
It seems like Yaoi\Command\Option::cre...amed()->setIsRequired() of type Yaoi\Command\Option is incompatible with the declared type string of property $schema.

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...
110
            ->setDescription('Path to JSON schema file')->setIsUnnamed()->setIsRequired();
111
112
        $options->ptrInSchema = Command\Option::create()->setType()->setIsVariadic()
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...
113
            ->setDescription('JSON pointers to structure in in root schema, default #');
114
115
        $options->defPtr = Command\Option::create()->setType()->setIsVariadic()
0 ignored issues
show
Documentation Bug introduced by
It seems like Yaoi\Command\Option::cre...default #/definitions') of type Yaoi\Command\Option is incompatible with the declared type string[] of property $defPtr.

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...
116
            ->setDescription('Definitions pointers to strip from symbol names, default #/definitions');
117
118
        $options->patches = Command\Option::create()->setType()->setIsVariadic()
0 ignored issues
show
Documentation Bug introduced by
It seems like Yaoi\Command\Option::cre...es are also supported') of type Yaoi\Command\Option is incompatible with the declared type string[] of property $patches.

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...
119
            ->setDescription('JSON patches to apply to schema file before processing, merge patches are also supported');
120
    }
121
122
    protected function loadSchema(&$skipRoot, &$baseName)
123
    {
124
        $dataValue = Base::readJsonOrYaml($this->schema, $this->response);
125
        if (!$dataValue) {
126
            $this->response->error('Unable to find schema in ' . $this->schema);
127
            die(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
128
        }
129
130
        if (!empty($this->patches)) {
131
            foreach ($this->patches as $patchPath) {
132
                $patch = Base::readJsonOrYaml($patchPath, $this->response);
133
                if (is_array($patch)) {
134
                    $jp = JsonPatch::import($patch);
135
                    try {
136
                        $jp->apply($dataValue);
137
                    } catch (Exception $e) {
138
                        throw new ExitCode($e->getMessage(), 1);
139
                    }
140
                }  else {
141
                    JsonMergePatch::apply($dataValue, $patch);
142
                }
143
            }
144
        }
145
146
        $resolver = new ResolverMux();
147
148
        $data = $dataValue;
149
        if (!empty($this->ptrInSchema)) {
150
            $baseName = basename($this->schema);
151
            $skipRoot = true;
152
            $preloaded = new Preloaded();
153
            $preloaded->setSchemaData($baseName, $dataValue);
154
            $resolver->resolvers[] = $preloaded;
155
            $data = new \stdClass();
156
            foreach ($this->ptrInSchema as $i => $ptr) {
157
                $data->oneOf[$i] = (object)[Schema::PROP_REF => $baseName . $ptr];
158
            }
159
        }
160
161
        $resolver->resolvers[] = new BasicFetcher();
162
        return Schema::import($data, new Context($resolver));
163
    }
164
}