Skip to content

Commit 14b2146

Browse files
committed
Implement complex oneOf + fix error 'Creating default object from empty value in PHP'
1 parent 1e7cea6 commit 14b2146

File tree

3 files changed

+42
-37
lines changed

3 files changed

+42
-37
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
},
2020
"require": {
2121
"php": "^7.4 || ^8.0",
22-
"cebe/php-openapi": "^1.5.0",
2322
"yiisoft/yii2": "~2.0.48",
2423
"yiisoft/yii2-gii": "~2.0.0 | ~2.1.0 | ~2.2.0| ~2.3.0",
2524
"laminas/laminas-code": ">=3.4 <=4.13",
2625
"php-openapi/yii2-fractal": "^1.0.0",
2726
"fakerphp/faker": "^1.9",
2827
"sam-it/yii2-mariadb": "^2.0",
29-
"symfony/var-exporter": "^5.4"
28+
"symfony/var-exporter": "^5.4",
29+
"cebe/php-openapi": "^1.7"
3030
},
3131
"require-dev": {
3232
"cebe/indent": "*",

src/lib/FakerStubResolver.php

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use cebe\openapi\exceptions\TypeErrorException;
1414
use cebe\openapi\exceptions\UnresolvableReferenceException;
15+
use cebe\openapi\ReferenceContext;
1516
use cebe\openapi\spec\Reference;
1617
use cebe\openapi\spec\Schema;
1718
use cebe\openapi\SpecObjectInterface;
@@ -22,6 +23,7 @@
2223
use cebe\yii2openapi\lib\openapi\PropertySchema;
2324
use Symfony\Component\VarExporter\Exception\ExceptionInterface;
2425
use Symfony\Component\VarExporter\VarExporter;
26+
use Yii;
2527
use yii\base\InvalidConfigException;
2628
use yii\helpers\Json;
2729
use yii\helpers\VarDumper;
@@ -100,6 +102,8 @@ public function resolve(): ?string
100102
} elseif ($this->attribute->phpType === 'array' ||
101103
substr($this->attribute->phpType, -2) === '[]') {
102104
$result = $this->fakeForArray($this->property->getProperty());
105+
} elseif ($this->attribute->phpType === 'object') {
106+
$result = $this->fakeForObject($this->property->getProperty());
103107
} else {
104108
return null;
105109
}
@@ -265,7 +269,7 @@ private function fakeForArray(SpecObjectInterface $property, int $count = 4): st
265269
$count = $maxItems;
266270
}
267271
}
268-
if (isset($property->uniqueItems)) {
272+
if (!empty($property->uniqueItems)) {
269273
$uniqueItems = $property->uniqueItems;
270274
}
271275

@@ -281,7 +285,7 @@ private function fakeForArray(SpecObjectInterface $property, int $count = 4): st
281285
if ($items instanceof Reference) {
282286
$class = str_replace('#/components/schemas/', '', $items->getReference());
283287
$class .= 'Faker';
284-
return $this->wrapAsArray('(new ' . $class . ')->generateModel()->attributes', false, $count);
288+
return $this->wrapInArray('(new ' . $class . ')->generateModel()->attributes', false, $count);
285289
} elseif (!empty($items->oneOf)) {
286290
return $this->handleOneOf($items, $count);
287291
}
@@ -293,15 +297,16 @@ private function fakeForArray(SpecObjectInterface $property, int $count = 4): st
293297
$aElementFaker = $this->aElementFaker($this->property->getProperty()->getSerializableData());
294298

295299
if (in_array($type, ['string', 'number', 'integer', 'boolean'])) {
296-
return $this->wrapAsArray($aElementFaker, $uniqueItems, $count);
300+
return $this->wrapInArray($aElementFaker, $uniqueItems, $count);
297301
}
298302

299303
if ($type === 'array') { # array or nested arrays
300304
return $this->{__FUNCTION__}($items);
301305
}
302306

303307
if ($type === 'object') {
304-
return $this->handleObject($items, $count);
308+
$result = $this->fakeForObject($items, $count);
309+
return $this->wrapInArray($result, $uniqueItems, $count);
305310
}
306311

307312

@@ -316,18 +321,9 @@ private function fakeForArray(SpecObjectInterface $property, int $count = 4): st
316321
}
317322

318323
/**
319-
* @param $items Schema|Reference|null
320-
* @param $count int
321-
* @param bool $nested
322-
* @return string
323-
* @throws ExceptionInterface
324-
* @throws InvalidConfigException
325-
* @throws InvalidDefinitionException
326-
* @throws TypeErrorException
327-
* @throws UnresolvableReferenceException
328324
* @internal
329325
*/
330-
public function handleObject(Schema $items, int $count, bool $nested = false): string
326+
public function fakeForObject(SpecObjectInterface $items): string
331327
{
332328
$props = '[' . PHP_EOL;
333329
$cs = new ComponentSchema($items, 'unnamed');
@@ -337,35 +333,24 @@ public function handleObject(Schema $items, int $count, bool $nested = false): s
337333
/** @var SpecObjectInterface $prop */
338334

339335
if ($prop->properties) { // object
340-
$result = $this->{__FUNCTION__}($prop, $count, true);
336+
$result = $this->{__FUNCTION__}($prop);
341337
} else {
342338
$ps = new PropertySchema($prop, $name, $cs);
343339
$attr = $dbModels->attributes[$name];
344-
$result = (string)((new static($attr, $ps))->resolve());
340+
$result = (string)((new static($attr, $ps, $this->config))->resolve());
345341
}
346342

347343
$props .= '\'' . $name . '\' => ' . $result . ',' . PHP_EOL;
348344
}
349345
$props .= ']';
350346

351-
if ($nested) {
352-
return $props;
353-
}
354-
355-
return 'array_map(function () use ($faker, $uniqueFaker) {
356-
return ' . $props . ';
357-
}, range(1, ' . $count . '))';
347+
return $props;
358348
}
359349

360350
/**
361351
* @param $items
362352
* @param $count
363353
* @return string
364-
* @throws ExceptionInterface
365-
* @throws InvalidConfigException
366-
* @throws InvalidDefinitionException
367-
* @throws TypeErrorException
368-
* @throws UnresolvableReferenceException
369354
* @internal
370355
*/
371356
public function handleOneOf($items, $count): string
@@ -374,8 +359,7 @@ public function handleOneOf($items, $count): string
374359
foreach ($items->oneOf as $key => $aDataType) {
375360
/** @var Schema|Reference $aDataType */
376361

377-
// $a1 = $this->fakeForArray($aDataType, 1);
378-
$a1 = $this->aElementFaker($aDataType->getSerializableData());
362+
$a1 = $this->aElementFaker(['items' => $aDataType->getSerializableData()]);
379363
$result .= '$dataType' . $key . ' = ' . $a1 . ';';
380364
}
381365
$ct = count($items->oneOf) - 1;
@@ -384,7 +368,7 @@ public function handleOneOf($items, $count): string
384368
return $result;
385369
}
386370

387-
public function wrapAsArray($aElementFaker, $uniqueItems, $count): string
371+
public function wrapInArray($aElementFaker, $uniqueItems, $count): string
388372
{
389373
return 'array_map(function () use ($faker, $uniqueFaker) {
390374
return ' . ($uniqueItems ? str_replace('$faker->', '$uniqueFaker->', $aElementFaker) : $aElementFaker) . ';
@@ -401,11 +385,19 @@ public function aElementFaker($data): ?string
401385
$aElementData = Json::decode(Json::encode($data));
402386
$compoSchemaData = [
403387
'properties' => [
404-
'unnamedProp' => $aElementData['items'] ?? $aElementData # later is used only in `oneOf`
388+
'unnamedProp' => $aElementData['items']
405389
]
406390
];
407-
$cs = new ComponentSchema(new Schema($compoSchemaData), 'UnnamedCompo');
408-
$dbModels = (new AttributeResolver('UnnamedCompo', $cs, new JunctionSchemas([])))->resolve();
409-
return (new static($dbModels->attributes['unnamedProp'], $cs->getProperty('unnamedProp')))->resolve();
391+
392+
$schema = new Schema($compoSchemaData);
393+
394+
if ($this->config) {
395+
$rc = new ReferenceContext($this->config->getOpenApi(), Yii::getAlias($this->config->openApiPath));
396+
$schema->setReferenceContext($rc);
397+
}
398+
399+
$cs = new ComponentSchema($schema, 'UnnamedCompo');
400+
$dbModels = (new AttributeResolver('UnnamedCompo', $cs, new JunctionSchemas([]), $this->config))->resolve();
401+
return (new static($dbModels->attributes['unnamedProp'], $cs->getProperty('unnamedProp'), $this->config))->resolve();
410402
}
411403
}

tests/specs/issue_fix/20_consider_openapi_spec_examples_in_faker_code_generation/index.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ components:
153153
one_of_arr:
154154
type: array # ["foo", 5, -2, "bar"]
155155
maxItems: 8
156+
items:
157+
oneOf:
158+
- type: integer
159+
- type: string
160+
- type: boolean
161+
162+
one_of_arr_complex:
163+
type: array
164+
maxItems: 8
156165
items:
157166
oneOf:
158167
- type: integer
@@ -166,6 +175,10 @@ components:
166175
properties:
167176
id:
168177
type: integer
178+
- type: array
179+
items:
180+
$ref: '#/components/schemas/User'
169181

170182

171183
# oneOf
184+
# TODO count is not working in some cases

0 commit comments

Comments
 (0)