Passed
Push — master ( 3eef21...137960 )
by Sys
02:03
created

Generator::toOpenApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace TgScraper;
4
5
use BadMethodCallException;
6
use Exception;
7
use InvalidArgumentException;
8
use JetBrains\PhpStorm\ArrayShape;
9
use PHPHtmlParser\Exceptions\ChildNotFoundException;
10
use PHPHtmlParser\Exceptions\CircularException;
11
use PHPHtmlParser\Exceptions\ContentLengthException;
12
use PHPHtmlParser\Exceptions\LogicalException;
13
use PHPHtmlParser\Exceptions\NotLoadedException;
14
use PHPHtmlParser\Exceptions\ParentNotFoundException;
15
use PHPHtmlParser\Exceptions\StrictException;
16
use Psr\Http\Client\ClientExceptionInterface;
17
use Psr\Log\LoggerInterface;
18
use Symfony\Component\Yaml\Yaml;
19
use TgScraper\Common\SchemaExtractor;
20
use TgScraper\Common\StubCreator;
21
use TgScraper\Constants\Versions;
22
use Throwable;
23
24
/**
25
 * Class Generator
26
 * @package TgScraper
27
 */
28
class Generator
29
{
30
31
    /**
32
     * Path to templates directory.
33
     */
34
    public const TEMPLATES_DIRECTORY = __DIR__ . '/../templates';
35
36
    /**
37
     * @var array
38
     */
39
    private array $schema;
40
41
    /**
42
     * Generator constructor.
43
     * @param LoggerInterface $logger
44
     * @param string $url
45
     * @param array|null $schema
46
     * @throws ChildNotFoundException
47
     * @throws CircularException
48
     * @throws ClientExceptionInterface
49
     * @throws ContentLengthException
50
     * @throws LogicalException
51
     * @throws NotLoadedException
52
     * @throws ParentNotFoundException
53
     * @throws StrictException
54
     * @throws Throwable
55
     */
56
    public function __construct(
57
        private LoggerInterface $logger,
58
        private string $url = Versions::LATEST,
59
        ?array $schema = null
60
    ) {
61
        if (empty($schema)) {
62
            try {
63
                $extractor = new SchemaExtractor($this->logger, $this->url);
64
                $this->logger->info('Schema not provided, extracting from URL.');
65
                $schema = $extractor->extract();
66
            } catch (Throwable $e) {
67
                $this->logger->critical(
68
                    'An exception occurred while trying to extract the schema: ' . $e->getMessage()
69
                );
70
                throw $e;
71
            }
72
        }
73
        /** @var array $schema */
74
        $this->schema = $schema;
75
    }
76
77
    /**
78
     * @throws ChildNotFoundException
79
     * @throws CircularException
80
     * @throws ParentNotFoundException
81
     * @throws StrictException
82
     * @throws ClientExceptionInterface
83
     * @throws NotLoadedException
84
     * @throws ContentLengthException
85
     * @throws LogicalException
86
     * @throws Throwable
87
     */
88
    public static function fromYaml(LoggerInterface $logger, string $yaml): self
89
    {
90
        $data = Yaml::parse($yaml);
91
        return new self($logger, schema: $data);
92
    }
93
94
    /**
95
     * @throws ChildNotFoundException
96
     * @throws ParentNotFoundException
97
     * @throws CircularException
98
     * @throws StrictException
99
     * @throws ClientExceptionInterface
100
     * @throws NotLoadedException
101
     * @throws ContentLengthException
102
     * @throws LogicalException
103
     * @throws Throwable
104
     */
105
    public static function fromJson(LoggerInterface $logger, string $json): self
106
    {
107
        $data = json_decode($json, true, flags: JSON_THROW_ON_ERROR);
108
        return new self($logger, schema: $data);
109
    }
110
111
    /**
112
     * @param string $directory
113
     * @param string $namespace
114
     * @return void
115
     * @throws Exception
116
     */
117
    public function toStubs(string $directory = '', string $namespace = 'TelegramApi'): void
118
    {
119
        try {
120
            $directory = self::getTargetDirectory($directory);
121
        } catch (Exception $e) {
122
            $this->logger->critical(
123
                'An exception occurred while trying to get the target directory: ' . $e->getMessage()
124
            );
125
            throw $e;
126
        }
127
        try {
128
            $creator = new StubCreator($this->schema, $namespace);
129
        } catch (InvalidArgumentException $e) {
130
            $this->logger->critical(
131
                'An exception occurred while trying to parse the schema: ' . $e->getMessage()
132
            );
133
            throw $e;
134
        }
135
        $code = $creator->generateCode();
136
        foreach ($code['types'] as $className => $type) {
137
            $this->logger->info('Generating class for Type: ' . $className);
138
            $filename = sprintf('%s/Types/%s.php', $directory, $className);
139
            file_put_contents($filename, $type);
140
        }
141
        file_put_contents($directory . '/API.php', $code['api']);
142
    }
143
144
    /**
145
     * @param string $path
146
     * @return string
147
     * @throws Exception
148
     */
149
    private static function getTargetDirectory(string $path): string
150
    {
151
        $result = realpath($path);
152
        if (false === $result) {
153
            if (!mkdir($path)) {
154
                $path = __DIR__ . '/../generated';
155
                if (!file_exists($path)) {
156
                    mkdir($path, 0755);
157
                }
158
            }
159
        }
160
        $result = realpath($path);
161
        if (false === $result) {
162
            throw new Exception('Could not create target directory');
163
        }
164
        @mkdir($result . '/Types', 0755);
165
        return $result;
166
    }
167
168
    /**
169
     * @param int $options
170
     * @return string
171
     */
172
    public function toJson(int $options = 0): string
173
    {
174
        return json_encode($this->schema, $options);
175
    }
176
177
    /**
178
     * @param int $inline
179
     * @param int $indent
180
     * @param int $flags
181
     * @return string
182
     */
183
    public function toYaml(int $inline = 6, int $indent = 4, int $flags = 0): string
184
    {
185
        return Yaml::dump($this->schema, $inline, $indent, $flags);
186
    }
187
188
    /**
189
     * @return string
190
     */
191
    public function toOpenApi(): string
192
    {
193
        throw new BadMethodCallException('Not implemented');
194
    }
195
196
197
    /**
198
     * Thanks to davtur19 (https://github.com/davtur19/TuriBotGen/blob/master/postman.php)
199
     * @param int $options
200
     * @return string
201
     */
202
    #[ArrayShape(['info' => "string[]", 'variable' => "string[]", 'item' => "array[]"])]
203
    public function toPostman(
204
        int $options = 0
205
    ): string {
206
        $template = file_get_contents(self::TEMPLATES_DIRECTORY . '/postman.json');
207
        $result = json_decode($template, true);
208
        $result['info']['version'] = $this->schema['version'];
209
        foreach ($this->schema['methods'] as $method) {
210
            $formData = [];
211
            if (!empty($method['fields'])) {
212
                foreach ($method['fields'] as $field) {
213
                    $formData[] = [
214
                        'key' => $field['name'],
215
                        'disabled' => !$field['required'],
216
                        'description' => sprintf(
217
                            '%s. %s',
218
                            $field['required'] ? 'Required' : 'Optional',
219
                            $field['description']
220
                        ),
221
                        'type' => 'text'
222
                    ];
223
                }
224
            }
225
            $result['item'][] = [
226
                'name' => $method['name'],
227
                'request' => [
228
                    'method' => 'POST',
229
                    'body' => [
230
                        'mode' => 'formdata',
231
                        'formdata' => $formData
232
                    ],
233
                    'url' => [
234
                        'raw' => 'https://api.telegram.org/bot{{token}}/' . $method['name'],
235
                        'protocol' => 'https',
236
                        'host' => [
237
                            'api',
238
                            'telegram',
239
                            'org'
240
                        ],
241
                        'path' => [
242
                            'bot{{token}}',
243
                            $method['name']
244
                        ]
245
                    ],
246
                    'description' => $method['description']
247
                ]
248
            ];
249
        }
250
        return json_encode($result, $options);
251
    }
252
253
}
254