Skip to content

Commit da76d16

Browse files
cussroxvearutop
authored andcommitted
Nullable properties (#26)
1 parent 989bc3a commit da76d16

28 files changed

+178
-111
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.2.21] - 2019-10-25
8+
9+
### Changed
10+
- Magical `phpdoc` for nullable properties instead of explicit properties.
11+
- Better property names collision resolution.
12+
713
## [0.2.20] - 2019-10-02
814

915
### Fixed
@@ -19,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1925
### Fixed
2026
- Description trimming bug.
2127

28+
[0.2.21]: https://github.com/swaggest/php-code-builder/compare/v0.2.20...v0.2.21
2229
[0.2.20]: https://github.com/swaggest/php-code-builder/compare/v0.2.19...v0.2.20
2330
[0.2.19]: https://github.com/swaggest/php-code-builder/compare/v0.2.18...v0.2.19
2431
[0.2.18]: https://github.com/swaggest/php-code-builder/compare/v0.2.17...v0.2.18

src/JsonSchema/PhpBuilder.php

+87-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Swaggest\JsonSchema\JsonSchema;
99
use Swaggest\JsonSchema\Schema;
1010
use Swaggest\JsonSchema\SchemaContract;
11+
use Swaggest\JsonSchema\SchemaExporter;
1112
use Swaggest\PhpCodeBuilder\Exception;
1213
use Swaggest\PhpCodeBuilder\PhpAnyType;
1314
use Swaggest\PhpCodeBuilder\PhpClass;
@@ -148,12 +149,19 @@ private function makeClass($schema, $path)
148149

149150
if ($schema->properties) {
150151
$phpNames = array();
152+
/**
153+
* @var string $name
154+
* @var Schema $property
155+
*/
151156
foreach ($schema->properties as $name => $property) {
152-
$i = '';
153-
do {
154-
$propertyName = PhpCode::makePhpName($name . $i);
155-
$i .= 'a';
156-
} while (isset($phpNames[$propertyName]));
157+
$propertyName = PhpCode::makePhpName($name);
158+
159+
$i = 2;
160+
$basePropertyName = $propertyName;
161+
while (isset($phpNames[$propertyName])) {
162+
$propertyName = $basePropertyName . $i;
163+
$i++;
164+
}
157165
$phpNames[$propertyName] = true;
158166

159167
$schemaBuilder = new SchemaBuilder($property, '$properties->' . $propertyName, $path . '->' . $name, $this);
@@ -163,9 +171,15 @@ private function makeClass($schema, $path)
163171
if ($this->makeEnumConstants) {
164172
$schemaBuilder->setSaveEnumConstInClass($class);
165173
}
166-
$phpProperty = new PhpClassProperty($propertyName, $this->getType($property, $path . '->' . $name));
174+
$propertyType = $this->getType($property, $path . '->' . $name);
175+
$phpProperty = new PhpClassProperty($propertyName, $propertyType);
167176
$phpProperty->addMeta($property, self::SCHEMA);
168177
$phpProperty->addMeta($name, self::PROPERTY_NAME);
178+
179+
if ($this->schemaIsNullable($property)) {
180+
$phpProperty->setIsMagical(true);
181+
}
182+
169183
if ($property->description) {
170184
$phpProperty->setDescription($property->description);
171185
}
@@ -261,6 +275,73 @@ public static function getSchemaMeta(AbstractTemplate $template)
261275
{
262276
return $template->getMeta(self::SCHEMA);
263277
}
278+
279+
/**
280+
* Returns true if null is allowed by schema.
281+
*
282+
* @param Schema $property
283+
* @return bool
284+
*/
285+
private function schemaIsNullable($property)
286+
{
287+
if (!empty($property->enum) && !in_array(null, $property->enum)) {
288+
return false;
289+
}
290+
291+
if ($property->const !== null) {
292+
return false;
293+
}
294+
295+
if (!empty($property->anyOf)) {
296+
$nullable = false;
297+
foreach ($property->anyOf as $item) {
298+
if ($item instanceof Schema) {
299+
if ($this->schemaIsNullable($item)) {
300+
$nullable = true;
301+
break;
302+
}
303+
}
304+
}
305+
if (!$nullable) {
306+
return false;
307+
}
308+
}
309+
310+
if (!empty($property->oneOf)) {
311+
$nullable = false;
312+
foreach ($property->oneOf as $item) {
313+
if ($item instanceof Schema) {
314+
if ($this->schemaIsNullable($item)) {
315+
$nullable = true;
316+
break;
317+
}
318+
}
319+
}
320+
if (!$nullable) {
321+
return false;
322+
}
323+
}
324+
325+
if (!empty($property->allOf)) {
326+
foreach ($property->allOf as $item) {
327+
if ($item instanceof Schema) {
328+
if (!$this->schemaIsNullable($item)) {
329+
return false;
330+
}
331+
}
332+
}
333+
}
334+
335+
if (
336+
$property->type === null
337+
|| $property->type === Schema::NULL
338+
|| (is_array($property->type) && in_array(Schema::NULL, $property->type))
339+
) {
340+
return true;
341+
}
342+
343+
return false;
344+
}
264345
}
265346

266347

src/PhpClass.php

+14
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ private function renderProperties()
7878
{
7979
$result = '';
8080
foreach ($this->properties as $property) {
81+
if ($property->isMagical()) {
82+
$nv = $property->getNamedVar();
83+
$typeString = PhpStdType::TYPE_MIXED;
84+
$type = $nv->getType();
85+
if ($type !== null) {
86+
$typeString = $type->renderPhpDocType();
87+
}
88+
89+
$this->getPhpDoc()->add(
90+
PhpDoc::TAG_PROPERTY,
91+
trim($typeString . ' $' . $nv->getName() . ' ' . $nv->getDescription())
92+
);
93+
continue;
94+
}
8195
$result .= $property->render();
8296
}
8397
return $result;

src/PhpClassProperty.php

+21
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,33 @@ class PhpClassProperty extends PhpTemplate
1515
/** @var PhpNamedVar */
1616
private $namedVar;
1717

18+
/** @var bool Magical property is rendered as phpdoc */
19+
private $isMagical = false;
20+
21+
/**
22+
* @return bool
23+
*/
24+
public function isMagical()
25+
{
26+
return $this->isMagical;
27+
}
28+
29+
/**
30+
* @param bool $isMagical
31+
*/
32+
public function setIsMagical($isMagical)
33+
{
34+
$this->isMagical = $isMagical;
35+
}
36+
1837
public function __construct($name, PhpAnyType $type = null, $visibility = PhpFlags::VIS_PUBLIC)
1938
{
2039
$this->namedVar = new PhpNamedVar($name, $type);
2140
$this->visibility = $visibility;
2241
}
2342

43+
44+
2445
/**
2546
* @param mixed $value
2647
* @return $this

tests/src/PHPUnit/JsonSchema/AdvancedTest.php

+21-21
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
5050
}
5151
}
5252
53+
/**
54+
* @property mixed $bar
55+
*/
5356
class RootOneOf0 extends Swaggest\JsonSchema\Structure\ClassStructure
5457
{
5558
/** @var mixed */
5659
public $foo;
5760
58-
/** @var mixed */
59-
public $bar;
60-
6161
/**
6262
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
6363
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -73,14 +73,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
7373
}
7474
}
7575
76+
/**
77+
* @property mixed $bar
78+
*/
7679
class RootOneOf1 extends Swaggest\JsonSchema\Structure\ClassStructure
7780
{
7881
/** @var mixed */
7982
public $foo;
8083
81-
/** @var mixed */
82-
public $bar;
83-
8484
/**
8585
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
8686
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -146,14 +146,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
146146
}
147147
}
148148
149+
/**
150+
* @property mixed $bar
151+
*/
149152
class RootAnyOf0 extends Swaggest\JsonSchema\Structure\ClassStructure
150153
{
151154
/** @var mixed */
152155
public $foo;
153156
154-
/** @var mixed */
155-
public $bar;
156-
157157
/**
158158
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
159159
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -169,14 +169,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
169169
}
170170
}
171171
172+
/**
173+
* @property mixed $bar
174+
*/
172175
class RootAnyOf1 extends Swaggest\JsonSchema\Structure\ClassStructure
173176
{
174177
/** @var mixed */
175178
public $foo;
176179
177-
/** @var mixed */
178-
public $bar;
179-
180180
/**
181181
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
182182
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -243,14 +243,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
243243
}
244244
}
245245
246+
/**
247+
* @property mixed $bar
248+
*/
246249
class RootAllOf0 extends Swaggest\JsonSchema\Structure\ClassStructure
247250
{
248251
/** @var mixed */
249252
public $foo;
250253
251-
/** @var mixed */
252-
public $bar;
253-
254254
/**
255255
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
256256
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -266,14 +266,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
266266
}
267267
}
268268
269+
/**
270+
* @property mixed $bar
271+
*/
269272
class RootAllOf1 extends Swaggest\JsonSchema\Structure\ClassStructure
270273
{
271274
/** @var mixed */
272275
public $foo;
273276
274-
/** @var mixed */
275-
public $bar;
276-
277277
/**
278278
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
279279
* @param Swaggest\JsonSchema\Schema $ownerSchema
@@ -334,14 +334,14 @@ public static function setUpProperties($properties, Swaggest\JsonSchema\Schema $
334334
}
335335
}
336336
337+
/**
338+
* @property mixed $bar
339+
*/
337340
class RootNot extends Swaggest\JsonSchema\Structure\ClassStructure
338341
{
339342
/** @var mixed */
340343
public $foo;
341344
342-
/** @var mixed */
343-
public $bar;
344-
345345
/**
346346
* @param Swaggest\JsonSchema\Constraint\Properties|static $properties
347347
* @param Swaggest\JsonSchema\Schema $ownerSchema

tests/src/Tmp/OpenAPI3/DefinitionsSchema.php

+2-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
/**
2020
* Built from #/definitions/Schema
21+
* @property mixed $default
22+
* @property mixed $example
2123
*/
2224
class DefinitionsSchema extends ClassStructure implements SchemaExporter
2325
{
@@ -113,9 +115,6 @@ class DefinitionsSchema extends ClassStructure implements SchemaExporter
113115
/** @var string */
114116
public $format;
115117

116-
/** @var mixed */
117-
public $default;
118-
119118
/** @var bool */
120119
public $nullable;
121120

@@ -128,9 +127,6 @@ class DefinitionsSchema extends ClassStructure implements SchemaExporter
128127
/** @var bool */
129128
public $writeOnly;
130129

131-
/** @var mixed */
132-
public $example;
133-
134130
/** @var ExternalDocumentation */
135131
public $externalDocs;
136132

tests/src/Tmp/OpenAPI3/Example.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
/**
1818
* Built from #/definitions/Example
19+
* @property mixed $value
1920
*/
2021
class Example extends ClassStructure
2122
{
@@ -27,9 +28,6 @@ class Example extends ClassStructure
2728
/** @var string */
2829
public $description;
2930

30-
/** @var mixed */
31-
public $value;
32-
3331
/** @var string */
3432
public $externalValue;
3533

tests/src/Tmp/OpenAPI3/HTTPSecuritySchemeNonBearer.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313

1414
/**
1515
* Non Bearer
16+
* @property mixed $scheme
1617
*/
1718
class HTTPSecuritySchemeNonBearer extends ClassStructure
1819
{
1920
const BEARER = 'bearer';
2021

21-
/** @var mixed */
22-
public $scheme;
23-
2422
/**
2523
* @param Properties|static $properties
2624
* @param Schema $ownerSchema

0 commit comments

Comments
 (0)