OpenApiGenerator::addMethod()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 20
rs 9.7333
cc 2
nc 2
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
            if (!empty($field['default'] ?? null)) {
84
                $schema['properties'][$name]['default'] = $field['default'];
85
            }
86
        }
87
        return $schema;
88
    }
89
90
    private static function parsePropertyTypes(array $types): array
91
    {
92
        $result = [];
93
        $hasMultipleTypes = count($types) > 1;
94
        foreach ($types as $type) {
95
            $type = self::parsePropertyType(trim($type));
96
            if ($hasMultipleTypes) {
97
                $result['anyOf'][] = $type;
98
                continue;
99
            }
100
            $result = $type;
101
        }
102
        return $result;
103
    }
104
105
    private static function parsePropertyType(string $type): array
106
    {
107
        if (str_starts_with($type, 'Array')) {
108
            return self::parsePropertyArray($type);
109
        }
110
        if (lcfirst($type) == $type) {
111
            $type = str_replace(['int', 'float', 'bool'], ['integer', 'number', 'boolean'], $type);
112
            return ['type' => $type];
113
        }
114
        return ['$ref' => '#/components/schemas/' . $type];
115
    }
116
117
    private static function parsePropertyArray(string $type): array
118
    {
119
        if (preg_match('/Array<(.+)>/', $type, $matches) === 1) {
120
            return [
121
                'type' => 'array',
122
                'items' => self::parsePropertyTypes(explode('|', $matches[1]))
123
            ];
124
        }
125
        return [];
126
    }
127
128
    /**
129
     * @return array
130
     */
131
    public function getData(): array
132
    {
133
        return $this->data;
134
    }
135
}