Skip to content

Commit 6a4b2b5

Browse files
committed
Add V31 Server Object and Server Variable Object
1 parent dd3457c commit 6a4b2b5

4 files changed

Lines changed: 600 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Membrane\OpenAPIReader\ValueObject\Valid\V31;
6+
7+
use Membrane\OpenAPIReader\Exception\InvalidOpenAPI;
8+
use Membrane\OpenAPIReader\Service\Url;
9+
use Membrane\OpenAPIReader\ValueObject\Partial;
10+
use Membrane\OpenAPIReader\ValueObject\Valid;
11+
use Membrane\OpenAPIReader\ValueObject\Valid\Identifier;
12+
use Membrane\OpenAPIReader\ValueObject\Valid\Validated;
13+
use Membrane\OpenAPIReader\ValueObject\Valid\Warning;
14+
15+
final class Server extends Validated implements Valid\Server
16+
{
17+
/** REQUIRED */
18+
public readonly string $url;
19+
20+
/**
21+
* When the url has a variable named in {brackets}
22+
* This array MUST contain the definition of the corresponding variable.
23+
* @var array<string,ServerVariable>
24+
* A map between variable name and its value
25+
*/
26+
public readonly array $variables;
27+
28+
public function __construct(
29+
Identifier $parentIdentifier,
30+
Partial\Server $server,
31+
) {
32+
if (!isset($server->url)) {
33+
throw InvalidOpenAPI::serverMissingUrl($parentIdentifier);
34+
}
35+
36+
$identifier = $parentIdentifier->append($server->url);
37+
parent::__construct($identifier);
38+
39+
$this->url = $this->validateUrl($identifier, $server->url);
40+
41+
$this->variables = $this->validateVariables(
42+
$this->getIdentifier(),
43+
$this->getVariableNames(),
44+
$server->variables,
45+
);
46+
}
47+
48+
public function getPattern(): string
49+
{
50+
$regex = preg_replace('#{[^/]+}#', '([^/]+)', $this->url);
51+
assert(is_string($regex));
52+
return $regex;
53+
}
54+
55+
public function getVariableNames(): array
56+
{
57+
preg_match_all('#{[^/]+}#', $this->url, $result);
58+
59+
return array_map(fn($v) => trim($v, '{}'), $result[0]);
60+
}
61+
62+
public function isConcrete(): bool
63+
{
64+
return empty($this->variables);
65+
}
66+
67+
public function isTemplated(): bool
68+
{
69+
return !empty($this->getVariableNames());
70+
}
71+
72+
private function validateUrl(Identifier $identifier, string $url): string
73+
{
74+
(new Url\ValidatesTemplate())($identifier, $url);
75+
76+
if (str_ends_with($url, '/') && $url !== '/') {
77+
$this->addWarning(
78+
'paths begin with a forward slash, so servers need not end in one',
79+
Warning::REDUNDANT_FORWARD_SLASH,
80+
);
81+
}
82+
83+
return rtrim($url, '/');
84+
}
85+
86+
/**
87+
* @param string[] $UrlVariableNames
88+
* @param Partial\ServerVariable[] $variables
89+
* @return array<string,ServerVariable>
90+
*/
91+
private function validateVariables(
92+
Identifier $identifier,
93+
array $UrlVariableNames,
94+
array $variables,
95+
): array {
96+
$result = [];
97+
foreach ($variables as $variable) {
98+
if (!isset($variable->name)) {
99+
throw InvalidOpenAPI::serverVariableMissingName($identifier);
100+
}
101+
102+
if (!in_array($variable->name, $UrlVariableNames)) {
103+
$this->addWarning(
104+
sprintf(
105+
'"variables" defines "%s" which is not found in "url".',
106+
$variable->name
107+
),
108+
Warning::REDUNDANT_VARIABLE
109+
);
110+
111+
continue;
112+
}
113+
114+
$result[$variable->name] = new ServerVariable(
115+
$identifier->append($variable->name),
116+
$variable
117+
);
118+
}
119+
120+
$undefined = array_diff($UrlVariableNames, array_keys($result));
121+
if (!empty($undefined)) {
122+
throw InvalidOpenAPI::serverHasUndefinedVariables(
123+
$identifier,
124+
...$undefined,
125+
);
126+
}
127+
128+
return $result;
129+
}
130+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Membrane\OpenAPIReader\ValueObject\Valid\V31;
6+
7+
use Membrane\OpenAPIReader\Exception\InvalidOpenAPI;
8+
use Membrane\OpenAPIReader\ValueObject\Partial;
9+
use Membrane\OpenAPIReader\ValueObject\Valid\Identifier;
10+
use Membrane\OpenAPIReader\ValueObject\Valid\Validated;
11+
use Membrane\OpenAPIReader\ValueObject\Valid\Warning;
12+
13+
final class ServerVariable extends Validated
14+
{
15+
/** REQUIRED */
16+
public readonly string $default;
17+
18+
/**
19+
* If not null:
20+
* - It SHOULD NOT be empty
21+
* - It SHOULD contain the "default" value
22+
* @var non-empty-list<string>|null
23+
*/
24+
public readonly array|null $enum;
25+
26+
public function __construct(
27+
Identifier $identifier,
28+
Partial\ServerVariable $serverVariable,
29+
) {
30+
parent::__construct($identifier);
31+
32+
if (!isset($serverVariable->default)) {
33+
throw InvalidOpenAPI::serverVariableMissingDefault($identifier);
34+
}
35+
36+
$this->default = $serverVariable->default;
37+
38+
if (isset($serverVariable->enum)) {
39+
if (empty($serverVariable->enum)) {
40+
$this->addWarning(
41+
'If "enum" is defined, it SHOULD NOT be empty',
42+
Warning::EMPTY_ENUM,
43+
);
44+
}
45+
46+
if (!in_array($serverVariable->default, $serverVariable->enum)) {
47+
$this->addWarning(
48+
'If "enum" is defined, the "default" SHOULD exist within it.',
49+
Warning::IMPOSSIBLE_DEFAULT
50+
);
51+
}
52+
}
53+
54+
$this->enum = $serverVariable->enum;
55+
}
56+
}

0 commit comments

Comments
 (0)