Passed
Pull Request — master (#34)
by Anatoly
02:11
created

OpenApi::setVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php declare(strict_types=1);
2
3
/**
4
 * It's free open-source software released under the MIT License.
5
 *
6
 * @author Anatoly Fenric <[email protected]>
7
 * @copyright Copyright (c) 2018, Anatoly Fenric
8
 * @license https://github.com/sunrise-php/http-router/blob/master/LICENSE
9
 * @link https://github.com/sunrise-php/http-router
10
 */
11
12
namespace Sunrise\Http\Router;
13
14
/**
15
 * Import classes
16
 */
17
use Doctrine\Common\Annotations\SimpleAnnotationReader;
18
use Sunrise\Http\Router\Annotation\OpenApi\AbstractReference;
19
use Sunrise\Http\Router\Annotation\OpenApi\Operation;
20
use Sunrise\Http\Router\Annotation\OpenApi\Parameter;
21
use Sunrise\Http\Router\Annotation\OpenApi\Schema;
22
use ReflectionClass;
23
24
/**
25
 * Import functions
26
 */
27
use function array_walk_recursive;
28
use function strtolower;
29
30
/**
31
 * OpenApi
32
 */
33
class OpenApi
34
{
35
36
    /**
37
     * Version of OpenAPI specification
38
     *
39
     * @var string
40
     */
41
    public const VERSION = '3.0.2';
42
43
    /**
44
     * @var SimpleAnnotationReader
45
     */
46
    private $annotationReader;
47
48
    /**
49
     * @var RouteInterface[]
50
     */
51
    private $routes = [];
52
53
    /**
54
     * @var string
55
     */
56
    private $title = 'REST API';
57
58
    /**
59
     * @var string
60
     */
61
    private $version = '0.0.1';
62
63
    /**
64
     * @var array
65
     */
66
    private $documentation = [];
67
68
    /**
69
     * Constructor of the class
70
     */
71
    public function __construct()
72
    {
73
        $this->annotationReader = new SimpleAnnotationReader();
74
        $this->annotationReader->addNamespace('Sunrise\Http\Router\Annotation');
75
    }
76
77
    /**
78
     * @param RouteInterface ...$routes
79
     *
80
     * @return void
81
     */
82
    public function addRoute(RouteInterface ...$routes) : void
83
    {
84
        foreach ($routes as $route) {
85
            $this->routes[] = $route;
86
        }
87
    }
88
89
    /**
90
     * @param string $title
91
     *
92
     * @return void
93
     */
94
    public function setTitle(string $title) : void
95
    {
96
        $this->title = $title;
97
    }
98
99
    /**
100
     * @param string $version
101
     *
102
     * @return void
103
     */
104
    public function setVersion(string $version) : void
105
    {
106
        $this->version = $version;
107
    }
108
109
    /**
110
     * @return void
111
     */
112
    public function generateDocumentation() : void
113
    {
114
        $this->documentation['openapi'] = self::VERSION;
115
        $this->documentation['info']['title'] = $this->title;
116
        $this->documentation['info']['version'] = $this->version;
117
118
        foreach ($this->routes as $route) {
119
            $path = path_plain($route->getPath());
0 ignored issues
show
Bug introduced by
The function path_plain was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

119
            $path = /** @scrutinizer ignore-call */ path_plain($route->getPath());
Loading history...
120
            $operation = $this->createOperation($route);
121
122
            foreach ($route->getMethods() as $method) {
123
                $method = strtolower($method);
124
125
                $this->documentation['paths'][$path][$method]['operationId'] = $route->getName();
126
                $this->documentation['paths'][$path][$method] += $operation->toArray();
127
            }
128
        }
129
130
        $this->handleReferences();
131
    }
132
133
    /**
134
     * @return array
135
     */
136
    public function toArray() : array
137
    {
138
        return $this->documentation;
139
    }
140
141
    /**
142
     * @return string
143
     */
144
    public function toJson() : string
145
    {
146
        return json_encode($this->documentation);
147
    }
148
149
    /**
150
     * @return string
151
     */
152
    public function toYaml() : string
153
    {
154
        return yaml_emit($this->documentation);
155
    }
156
157
    /**
158
     * @param RouteInterface $route
159
     *
160
     * @return Operation
161
     */
162
    private function createOperation(RouteInterface $route) : Operation
163
    {
164
        $target = new ReflectionClass($route->getRequestHandler());
165
        $operation = $this->annotationReader->getClassAnnotation($target, Operation::class) ?? new Operation();
166
        $attributes = path_parse($route->getPath());
0 ignored issues
show
Bug introduced by
The function path_parse was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

166
        $attributes = /** @scrutinizer ignore-call */ path_parse($route->getPath());
Loading history...
167
168
        foreach ($attributes as $attribute) {
169
            $parameter = new Parameter();
170
            $parameter->in = 'path';
171
            $parameter->name = $attribute['name'];
172
            $parameter->required = !$attribute['isOptional'];
173
174
            if (isset($attribute['pattern'])) {
175
                $parameter->schema = new Schema();
176
                $parameter->schema->type = 'string';
177
                $parameter->schema->pattern = $attribute['pattern'];
178
            }
179
180
            $operation->parameters[] = $parameter;
181
        }
182
183
        return $operation;
184
    }
185
186
    /**
187
     * @return void
188
     */
189
    private function handleReferences() : void
190
    {
191
        array_walk_recursive($this->documentation, function (&$value) {
192
            if (!($value instanceof AbstractReference)) {
193
                return;
194
            }
195
196
            $ref = $value;
197
            $value = $ref->getComponentPath();
198
199
            $component =& $this->documentation['components'][$ref->getComponentName()];
200
            if (isset($component[$ref->name])) {
201
                return;
202
            }
203
204
            $annotation = $ref->getAnnotation($this->annotationReader);
205
            if (!isset($annotation)) {
206
                return;
207
            }
208
209
            $component[$ref->name] = $annotation->toArray();
210
        });
211
    }
212
}
213