Passed
Push — master ( 137960...4d87d9 )
by Sys
11:11
created

OpenApiGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 4
1
<?php
2
3
namespace TgScraper\Common;
4
5
class OpenApiGenerator
6
{
7
8
9
    public function __construct(private array $defaultResponses, private array $data, array $types, array $methods)
10
    {
11
        $this->addTypes($types);
12
        $this->addMethods($methods);
13
    }
14
15
    public function setVersion($version = '1.0.0'): self
16
    {
17
        $this->data['info']['version'] = $version;
18
        return $this;
19
    }
20
21
    public function addMethods(array $methods): self
22
    {
23
        foreach ($methods as $method) {
24
            $this->addMethod($method['name'], $method['description'], $method['fields'], $method['return_types']);
25
        }
26
        return $this;
27
    }
28
29
    public function addMethod(string $name, string $description, array $fields, array $returnTypes): self
30
    {
31
        $method = '/' . $name;
32
        $this->data['paths'][$method] = ['description' => $description];
33
        $path = [];
34
        $fields = self::addFields(['type' => 'object'], $fields);
35
        $content = ['schema' => $fields];
36
        if (!empty($fields['required'])) {
37
            $path['requestBody']['required'] = true;
38
        }
39
        $path['requestBody']['content'] = [
40
            'application/json' => $content,
41
            'application/x-www-form-urlencoded' => $content,
42
            'multipart/form-data' => $content
43
        ];
44
        $path['responses'] = $this->defaultResponses;
45
        $path['responses']['200']['content']['application/json']['schema']
46
        ['allOf'][1]['properties']['result'] = self::parsePropertyTypes($returnTypes);
47
        $this->data['paths'][$method]['post'] = $path;
48
        return $this;
49
    }
50
51
    public function addTypes(array $types): self
52
    {
53
        foreach ($types as $type) {
54
            $this->addType($type['name'], $type['description'], $type['fields'], $type['extended_by']);
55
        }
56
        return $this;
57
    }
58
59
    public function addType(string $name, string $description, array $fields, array $extendedBy): self
60
    {
61
        $schema = ['description' => $description];
62
        $schema = self::addFields($schema, $fields);
63
        $this->data['components']['schemas'][$name] = $schema;
64
        if (!empty($extendedBy)) {
65
            foreach ($extendedBy as $extendedType) {
66
                $this->data['components']['schemas'][$name]['anyOf'][] = self::parsePropertyType($extendedType);
67
            }
68
            return $this;
69
        }
70
        $this->data['components']['schemas'][$name]['type'] = 'object';
71
        return $this;
72
    }
73
74
    private static function addFields(array $schema, array $fields): array
75
    {
76
        foreach ($fields as $field) {
77
            $name = $field['name'];
78
            $required = !$field['optional'];
79
            if ($required) {
80
                $schema['required'][] = $name;
81
            }
82
            $schema['properties'][$name] = self::parsePropertyTypes($field['types']);
83
        }
84
        return $schema;
85
    }
86
87
    private static function parsePropertyTypes(array $types): array
88
    {
89
        $result = [];
90
        $hasMultipleTypes = count($types) > 1;
91
        foreach ($types as $type) {
92
            $type = self::parsePropertyType(trim($type));
93
            if ($hasMultipleTypes) {
94
                $result['anyOf'][] = $type;
95
                continue;
96
            }
97
            $result = $type;
98
        }
99
        return $result;
100
    }
101
102
    private static function parsePropertyType(string $type): array
103
    {
104
        if (str_starts_with($type, 'Array')) {
105
            return self::parsePropertyArray($type);
106
        }
107
        if (lcfirst($type) == $type) {
108
            $type = str_replace(['int', 'float', 'bool'], ['integer', 'number', 'boolean'], $type);
109
            return ['type' => $type];
110
        }
111
        return ['$ref' => '#/components/schemas/' . $type];
112
    }
113
114
    private static function parsePropertyArray(string $type): array
115
    {
116
        if (preg_match('/Array<(.+)>/', $type, $matches) === 1) {
117
            return [
118
                'type' => 'array',
119
                'items' => self::parsePropertyTypes(explode(',', $matches[1]))
120
            ];
121
        }
122
        return [];
123
    }
124
125
    /**
126
     * @return array
127
     */
128
    public function getData(): array
129
    {
130
        return $this->data;
131
    }
132
}