Skip to content

Commit 06f5166

Browse files
authored
Fix cebe#162 - Bug $ref with x-faker (cebe#164)
Fix cebe#162 PR in fork: SOHELAHMED7#30
2 parents fbaa3bc + f394045 commit 06f5166

File tree

14 files changed

+461
-2
lines changed

14 files changed

+461
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
/.php_cs.cache
55
/.env
66
/.phpunit.result.cache
7+
8+
/.idea

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,40 @@ You may specify custom PHP code for generating fake data for a property:
104104
x-faker: "$faker->randomElements(['one', 'two', 'three', 'four'])"
105105
```
106106
107+
To avoid generating faker code for particular model attribute, use value `false`:
108+
109+
```yaml
110+
Post:
111+
properties:
112+
age:
113+
type: integer
114+
x-faker: false
115+
```
116+
117+
Using in reference with `allOf`:
118+
119+
```yaml
120+
Invoice:
121+
type: object
122+
required:
123+
- id
124+
properties:
125+
id:
126+
type: integer
127+
128+
Order:
129+
type: object
130+
required:
131+
- id
132+
properties:
133+
id:
134+
type: integer
135+
invoice:
136+
allOf:
137+
- $ref: '#/components/schemas/Invoice'
138+
- x-faker: false
139+
```
140+
107141
### `x-table`
108142

109143
Specify the table name for a Schema that defines a model which is stored in the database.

src/lib/FakerStubResolver.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,19 @@ public function __construct(Attribute $attribute, PropertySchema $property, ?Con
4444

4545
public function resolve():?string
4646
{
47+
if ($this->property->xFaker === false) {
48+
$this->attribute->setFakerStub(null);
49+
return null;
50+
}
4751
if ($this->property->hasAttr(CustomSpecAttr::FAKER)) {
48-
return $this->property->getAttr(CustomSpecAttr::FAKER);
52+
$fakerVal = $this->property->getAttr(CustomSpecAttr::FAKER);
53+
if ($fakerVal === false) {
54+
$this->attribute->setFakerStub(null);
55+
return null;
56+
}
57+
return $fakerVal;
4958
}
59+
5060
if ($this->attribute->isReadOnly() && $this->attribute->isVirtual()) {
5161
return null;
5262
}

src/lib/openapi/PropertySchema.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ class PropertySchema
4646
*/
4747
public $fkColName;
4848

49+
/**
50+
* @var null|bool|string
51+
* If `false`, no faker will be generated in faker model
52+
* See more about usage in README.md file present in root directory of the project
53+
*/
54+
public $xFaker;
55+
4956
/**
5057
* @var \cebe\openapi\SpecObjectInterface
5158
*/
@@ -93,7 +100,7 @@ public function __construct(SpecObjectInterface $property, string $name, Compone
93100
$this->schema = $schema;
94101
$this->isPk = $name === $schema->getPkName();
95102

96-
$onUpdate = $onDelete = $reference = $fkColName = null;
103+
$onUpdate = $onDelete = $xFaker = $reference = $fkColName = null;
97104

98105
foreach ($property->allOf ?? [] as $element) {
99106
// x-fk-on-delete | x-fk-on-update
@@ -103,6 +110,11 @@ public function __construct(SpecObjectInterface $property, string $name, Compone
103110
if (!empty($element->{CustomSpecAttr::FK_ON_DELETE})) {
104111
$onDelete = $element->{CustomSpecAttr::FK_ON_DELETE};
105112
}
113+
114+
if (isset($element->{CustomSpecAttr::FAKER})) {
115+
$xFaker = $element->{CustomSpecAttr::FAKER};
116+
}
117+
106118
if ($element instanceof Reference) {
107119
$reference = $element;
108120
}
@@ -128,6 +140,10 @@ public function __construct(SpecObjectInterface $property, string $name, Compone
128140
$this->fkColName = $fkColName;
129141
$this->property = $reference;
130142
$property = $this->property;
143+
} elseif ($xFaker !== null && $reference instanceof Reference) {
144+
$this->xFaker = $xFaker;
145+
$this->property = $reference;
146+
$property = $this->property;
131147
}
132148

133149
if ($property instanceof Reference) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
return [
4+
'openApiPath' => '@specs/issue_fix/162_bug_dollarref_with_x_faker/162_bug_dollarref_with_x_faker.yaml',
5+
'generateUrls' => false,
6+
'generateModels' => true,
7+
'excludeModels' => [
8+
'Error',
9+
],
10+
'generateControllers' => false,
11+
'generateMigrations' => false,
12+
'generateModelFaker' => true, // `generateModels` must be `true` in orde to use `generateModelFaker` as `true`
13+
];
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
openapi: 3.0.3
2+
# Edit this schema and start your project
3+
# This is sample schema
4+
# To generate code which is based on this schema
5+
# run commands mentioned Development section in README.md file
6+
info:
7+
title: 'Proxy-Service'
8+
description: ""
9+
version: 1.0.0
10+
contact:
11+
name: '...'
12+
email: you@example.com
13+
paths:
14+
/:
15+
get:
16+
summary: List
17+
operationId: list
18+
responses:
19+
'200':
20+
description: The information
21+
servers:
22+
- url: 'http://localhost:9937'
23+
description: 'Local Dev API'
24+
security:
25+
- BasicAuth: []
26+
components:
27+
securitySchemes:
28+
BasicAuth:
29+
type: http
30+
scheme: basic
31+
schemas:
32+
33+
Invoice:
34+
type: object
35+
required:
36+
- id
37+
properties:
38+
id:
39+
type: integer
40+
41+
Order:
42+
type: object
43+
required:
44+
- id
45+
properties:
46+
id:
47+
type: integer
48+
name:
49+
type: string
50+
name2:
51+
type: string
52+
x-faker: false
53+
invoice:
54+
allOf:
55+
- $ref: '#/components/schemas/Invoice'
56+
- x-faker: false
57+
# - nullable: true
58+
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
namespace app\models;
4+
5+
use Faker\Factory as FakerFactory;
6+
use Faker\Generator;
7+
use Faker\UniqueGenerator;
8+
9+
/**
10+
* Base fake data generator
11+
*/
12+
abstract class BaseModelFaker
13+
{
14+
/**
15+
* @var Generator
16+
*/
17+
protected $faker;
18+
/**
19+
* @var UniqueGenerator
20+
*/
21+
protected $uniqueFaker;
22+
23+
public function __construct()
24+
{
25+
$this->faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language));
26+
$this->uniqueFaker = new UniqueGenerator($this->faker);
27+
}
28+
29+
abstract public function generateModel($attributes = []);
30+
31+
public function getFaker():Generator
32+
{
33+
return $this->faker;
34+
}
35+
36+
public function getUniqueFaker():UniqueGenerator
37+
{
38+
return $this->uniqueFaker;
39+
}
40+
41+
public function setFaker(Generator $faker):void
42+
{
43+
$this->faker = $faker;
44+
}
45+
46+
public function setUniqueFaker(UniqueGenerator $faker):void
47+
{
48+
$this->uniqueFaker = $faker;
49+
}
50+
51+
/**
52+
* Generate and return model
53+
* @param array|callable $attributes
54+
* @param UniqueGenerator|null $uniqueFaker
55+
* @return \yii\db\ActiveRecord
56+
* @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']);
57+
* @example MyFaker::makeOne( function($model, $faker) {
58+
* $model->scenario = 'create';
59+
* $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]);
60+
* return $model;
61+
* });
62+
*/
63+
public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null)
64+
{
65+
$fakeBuilder = new static();
66+
if ($uniqueFaker !== null) {
67+
$fakeBuilder->setUniqueFaker($uniqueFaker);
68+
}
69+
$model = $fakeBuilder->generateModel($attributes);
70+
return $model;
71+
}
72+
73+
/**
74+
* Generate, save and return model
75+
* @param array|callable $attributes
76+
* @param UniqueGenerator|null $uniqueFaker
77+
* @return \yii\db\ActiveRecord
78+
* @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']);
79+
* @example MyFaker::saveOne( function($model, $faker) {
80+
* $model->scenario = 'create';
81+
* $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]);
82+
* return $model;
83+
* });
84+
*/
85+
public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null)
86+
{
87+
$model = static::makeOne($attributes, $uniqueFaker);
88+
$model->save();
89+
return $model;
90+
}
91+
92+
/**
93+
* Generate and return multiple models
94+
* @param int $number
95+
* @param array|callable $commonAttributes
96+
* @return \yii\db\ActiveRecord[]|array
97+
* @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]);
98+
* @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) {
99+
* $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]);
100+
* return $model;
101+
* });
102+
*/
103+
public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array
104+
{
105+
if ($number < 1) {
106+
return [];
107+
}
108+
$fakeBuilder = new static();
109+
if ($uniqueFaker !== null) {
110+
$fakeBuilder->setUniqueFaker($uniqueFaker);
111+
}
112+
return array_map(function () use ($commonAttributes, $fakeBuilder) {
113+
$model = $fakeBuilder->generateModel($commonAttributes);
114+
return $model;
115+
}, range(0, $number -1));
116+
}
117+
118+
/**
119+
* Generate, save and return multiple models
120+
* @param int $number
121+
* @param array|callable $commonAttributes
122+
* @return \yii\db\ActiveRecord[]|array
123+
* @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]);
124+
* @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) {
125+
* $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]);
126+
* return $model;
127+
* });
128+
*/
129+
public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array
130+
{
131+
if ($number < 1) {
132+
return [];
133+
}
134+
$fakeBuilder = new static();
135+
if ($uniqueFaker !== null) {
136+
$fakeBuilder->setUniqueFaker($uniqueFaker);
137+
}
138+
return array_map(function () use ($commonAttributes, $fakeBuilder) {
139+
$model = $fakeBuilder->generateModel($commonAttributes);
140+
$model->save();
141+
return $model;
142+
}, range(0, $number -1));
143+
}
144+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace app\models;
4+
5+
class Invoice extends \app\models\base\Invoice
6+
{
7+
8+
9+
}
10+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
namespace app\models;
3+
4+
use Faker\UniqueGenerator;
5+
6+
/**
7+
* Fake data generator for Invoice
8+
* @method static Invoice makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null);
9+
* @method static Invoice saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null);
10+
* @method static Invoice[] make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null)
11+
* @method static Invoice[] save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null)
12+
*/
13+
class InvoiceFaker extends BaseModelFaker
14+
{
15+
16+
/**
17+
* @param array|callable $attributes
18+
* @return Invoice|\yii\db\ActiveRecord
19+
* @example
20+
* $model = (new PostFaker())->generateModels(['author_id' => 1]);
21+
* $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) {
22+
* $model->scenario = 'create';
23+
* $model->author_id = 1;
24+
* return $model;
25+
* });
26+
**/
27+
public function generateModel($attributes = [])
28+
{
29+
$faker = $this->faker;
30+
$uniqueFaker = $this->uniqueFaker;
31+
$model = new Invoice();
32+
//$model->id = $uniqueFaker->numberBetween(0, 1000000);
33+
if (!is_callable($attributes)) {
34+
$model->setAttributes($attributes, false);
35+
} else {
36+
$model = $attributes($model, $faker, $uniqueFaker);
37+
}
38+
return $model;
39+
}
40+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace app\models;
4+
5+
class Order extends \app\models\base\Order
6+
{
7+
8+
9+
}
10+

0 commit comments

Comments
 (0)