77
88/** @noinspection InterfacesAsConstructorDependenciesInspection */
99/** @noinspection PhpUndefinedFieldInspection */
10+
1011namespace cebe \yii2openapi \lib ;
1112
13+ use cebe \openapi \exceptions \TypeErrorException ;
14+ use cebe \openapi \exceptions \UnresolvableReferenceException ;
1215use cebe \openapi \spec \Reference ;
1316use cebe \openapi \spec \Schema ;
1417use cebe \openapi \SpecObjectInterface ;
18+ use cebe \yii2openapi \lib \exceptions \InvalidDefinitionException ;
1519use cebe \yii2openapi \lib \items \Attribute ;
1620use cebe \yii2openapi \lib \items \JunctionSchemas ;
1721use cebe \yii2openapi \lib \openapi \ComponentSchema ;
1822use cebe \yii2openapi \lib \openapi \PropertySchema ;
23+ use Symfony \Component \VarExporter \Exception \ExceptionInterface ;
1924use Symfony \Component \VarExporter \VarExporter ;
25+ use yii \base \InvalidConfigException ;
26+ use yii \helpers \Json ;
2027use yii \helpers \VarDumper ;
2128use function str_replace ;
2229use const PHP_EOL ;
2835class FakerStubResolver
2936{
3037 public const MAX_INT = 1000000 ;
31- /**
32- * @var \cebe\yii2openapi\lib\items\Attribute
33- */
34- private $ attribute ;
3538
36- /**
37- * @var \cebe\yii2openapi\lib\openapi\PropertySchema
38- */
39- private $ property ;
39+ private Attribute $ attribute ;
4040
41- /** @var Config */
42- private $ config ;
41+ private PropertySchema $ property ;
42+
43+ private ?Config $ config ;
4344
4445 public function __construct (Attribute $ attribute , PropertySchema $ property , ?Config $ config = null )
4546 {
@@ -48,7 +49,14 @@ public function __construct(Attribute $attribute, PropertySchema $property, ?Con
4849 $ this ->config = $ config ;
4950 }
5051
51- public function resolve ():?string
52+ /**
53+ * @throws InvalidConfigException
54+ * @throws TypeErrorException
55+ * @throws UnresolvableReferenceException
56+ * @throws InvalidDefinitionException
57+ * @throws ExceptionInterface
58+ */
59+ public function resolve (): ?string
5260 {
5361 if ($ this ->property ->xFaker === false ) {
5462 $ this ->attribute ->setFakerStub (null );
@@ -74,9 +82,9 @@ public function resolve():?string
7482 $ config = new Config ;
7583 }
7684 $ mn = $ config ->modelNamespace ;
77- return '$faker->randomElement( \\' . $ mn
78- . ($ mn ? '\\' : '' )
79- . ucfirst ($ this ->attribute ->reference ). '::find()->select("id")->column()) ' ;
85+ return '$faker->randomElement( \\' . $ mn
86+ . ($ mn ? '\\' : '' )
87+ . ucfirst ($ this ->attribute ->reference ) . '::find()->select("id")->column()) ' ;
8088 }
8189
8290 $ limits = $ this ->attribute ->limits ;
@@ -96,18 +104,18 @@ public function resolve():?string
96104 return null ;
97105 }
98106
99- if (! $ this ->property ->hasAttr ('example ' )) {
107+ if (!$ this ->property ->hasAttr ('example ' )) {
100108 return $ result ;
101109 }
102110 if (stripos ($ result , 'uniqueFaker ' ) !== false ) {
103111 return $ result ;
104112 }
105113 $ example = $ this ->property ->getAttr ('example ' );
106114 $ example = VarExporter::export ($ example );
107- return str_replace ('$faker-> ' , '$faker->optional(0.92, ' . $ example. ')-> ' , $ result );
115+ return str_replace ('$faker-> ' , '$faker->optional(0.92, ' . $ example . ')-> ' , $ result );
108116 }
109117
110- private function fakeForString ():?string
118+ private function fakeForString (): ?string
111119 {
112120 $ formats = [
113121 'date ' => '$faker->dateTimeThisCentury->format( \'Y-m-d \') ' ,
@@ -127,7 +135,7 @@ private function fakeForString():?string
127135 }
128136 $ enum = $ this ->property ->getAttr ('enum ' );
129137 if (!empty ($ enum ) && is_array ($ enum )) {
130- $ items = str_replace ([PHP_EOL , ' ' ,',] ' ], ['' , '' , '] ' ], VarDumper::export ($ enum ));
138+ $ items = str_replace ([PHP_EOL , ' ' , ',] ' ], ['' , '' , '] ' ], VarDumper::export ($ enum ));
131139 return '$faker->randomElement( ' . $ items . ') ' ;
132140 }
133141 if ($ this ->attribute ->columnName === 'title '
@@ -172,7 +180,7 @@ private function fakeForString():?string
172180 '~(url|site|website|href)~i ' => '$faker->url ' ,
173181 '~(username|login)~i ' => '$faker->userName ' ,
174182 ];
175- $ size = $ this ->attribute ->size > 0 ? $ this ->attribute ->size : null ;
183+ $ size = $ this ->attribute ->size > 0 ? $ this ->attribute ->size : null ;
176184 foreach ($ patterns as $ pattern => $ fake ) {
177185 if (preg_match ($ pattern , $ this ->attribute ->columnName )) {
178186 if ($ size ) {
@@ -187,27 +195,27 @@ private function fakeForString():?string
187195 if ($ size < 5 ) {
188196 $ method = 'word ' ;
189197 }
190- return 'substr($faker-> ' . $ method. '( ' . $ size . '), 0, ' . $ size . ') ' ;
198+ return 'substr($faker-> ' . $ method . '( ' . $ size . '), 0, ' . $ size . ') ' ;
191199 }
192200 return '$faker->sentence ' ;
193201 }
194202
195- private function fakeForInt (?int $ min , ?int $ max ):?string
203+ private function fakeForInt (?int $ min , ?int $ max ): ?string
196204 {
197205 $ fakerVariable = 'faker ' ;
198206 if (preg_match ('~_?id$~ ' , $ this ->attribute ->columnName )) {
199207 $ fakerVariable = 'uniqueFaker ' ;
200208 }
201209 if ($ min !== null && $ max !== null ) {
202- return "\${ $ fakerVariable} ->numberBetween( $ min, $ max) " ;
210+ return "\$$ fakerVariable ->numberBetween ( $ min, $ max) " ;
203211 }
204212
205213 if ($ min !== null ) {
206- return "\${ $ fakerVariable} ->numberBetween( $ min, " . self ::MAX_INT . ") " ;
214+ return "\$$ fakerVariable ->numberBetween ( $ min, " . self ::MAX_INT . ") " ;
207215 }
208216
209217 if ($ max !== null ) {
210- return "\${ $ fakerVariable} ->numberBetween(0, $ max) " ;
218+ return "\$$ fakerVariable ->numberBetween (0, $ max) " ;
211219 }
212220
213221 $ patterns = [
@@ -221,10 +229,10 @@ private function fakeForInt(?int $min, ?int $max):?string
221229 return $ fake ;
222230 }
223231 }
224- return "\${ $ fakerVariable} ->numberBetween(0, " . self ::MAX_INT . ") " ;
232+ return "\$$ fakerVariable ->numberBetween (0, " . self ::MAX_INT . ") " ;
225233 }
226234
227- private function fakeForFloat (?int $ min , ?int $ max ):?string
235+ private function fakeForFloat (?int $ min , ?int $ max ): ?string
228236 {
229237 if ($ min !== null && $ max !== null ) {
230238 return "\$faker->randomFloat(null, $ min, $ max) " ;
@@ -238,69 +246,74 @@ private function fakeForFloat(?int $min, ?int $max):?string
238246 return '$faker->randomFloat() ' ;
239247 }
240248
249+ /**
250+ * @throws InvalidConfigException
251+ * @throws TypeErrorException
252+ * @throws UnresolvableReferenceException
253+ * @throws InvalidDefinitionException|ExceptionInterface
254+ */
241255 private function fakeForArray (SpecObjectInterface $ property , int $ count = 4 ): string
242256 {
243- // TODO consider example of OpenAPI spec
244- $ arbitrary = false ;
245257 $ uniqueItems = false ;
258+ $ arbitrary = false ;
246259 $ type = null ;
260+ if ($ property ->minItems ) {
261+ $ count = $ property ->minItems ;
262+ }
263+ if ($ property ->maxItems ) {
264+ $ maxItems = $ property ->maxItems ;
265+ if ($ maxItems < $ count ) {
266+ $ count = $ maxItems ;
267+ }
268+ }
269+ if (isset ($ property ->uniqueItems )) {
270+ $ uniqueItems = $ property ->uniqueItems ;
271+ }
272+
273+ // TODO consider example of OpenAPI spec
274+
247275// $count = 4; # let's set a number to default number of elements
248276
249277 /** @var Schema|Reference|null $items */
250278 $ items = $ property ->items ?? $ property ; # later is used in `oneOf`
251279
280+ $ aElementData = Json::decode (Json::encode ($ this ->property ->getProperty ()->getSerializableData ()));
281+ $ compoSchemaArr = [
282+ 'properties ' => [
283+ 'unnamedProp ' => $ aElementData ['items ' ]
284+ ]
285+ ];
286+
252287 if ($ items ) {
253288 if ($ items instanceof Reference) {
254289 $ class = str_replace ('#/components/schemas/ ' , '' , $ items ->getReference ());
255290 $ class .= 'Faker ' ;
256- return '(new ' . $ class . ')->generateModel()->attributes ' ;
291+ return $ this -> wrapAsArray ( '(new ' . $ class . ')->generateModel()->attributes ' , false , $ count ) ;
257292 } elseif (!empty ($ items ->oneOf )) {
258293 return $ this ->handleOneOf ($ items , $ count );
259294 } else {
260295 $ type = $ items ->type ;
261296 if ($ type === null ) {
262297 $ arbitrary = true ;
263298 }
299+ $ cs = new ComponentSchema (new Schema ($ compoSchemaArr ), 'UnnamedCompo ' );
300+ $ dbModels = (new AttributeResolver ('UnnamedCompo ' , $ cs , new JunctionSchemas ([])))->resolve ();
301+ $ aElementFaker = (new static ($ dbModels ->attributes ['unnamedProp ' ], $ cs ->getProperty ('unnamedProp ' )))->resolve ();
264302 }
265303 } else {
266304 $ arbitrary = true ;
267305 }
268306
269- if ($ property -> minItems ) {
270- $ count = $ property -> minItems ;
307+ if ($ arbitrary ) {
308+ return ' $faker->words() ' ;
271309 }
272310
273- if ($ property ->maxItems ) {
274- $ maxItems = $ property ->maxItems ;
275- if ($ maxItems < $ count ) {
276- $ count = $ maxItems ;
277- }
278- }
279-
280- if (isset ($ property ->uniqueItems )) {
281- $ uniqueItems = $ property ->uniqueItems ;
282- }
283-
284- if ($ arbitrary || $ type === 'string ' ) {
285- return ($ uniqueItems ? '$uniqueFaker ' : '$faker ' ) . '->words( ' . $ count . ') ' ;
286- }
287-
288- if (in_array ($ type , ['number ' , 'integer ' ])) {
289- return 'array_map(function () use ($faker, $uniqueFaker) {
290- return ' . ($ uniqueItems ? '$uniqueFaker ' : '$faker ' ) . '->randomNumber();
291- }, range(1, ' . $ count . ')) ' ;
292- }
293-
294- if ($ type === 'boolean ' ) {
295- return 'array_map(function () use ($faker, $uniqueFaker) {
296- return ' . ($ uniqueItems ? '$uniqueFaker ' : '$faker ' ) . '->boolean();
297- }, range(1, ' . $ count . ')) ' ;
311+ if (in_array ($ type , ['string ' , 'number ' , 'integer ' , 'boolean ' ])) {
312+ return $ this ->wrapAsArray ($ aElementFaker , $ uniqueItems , $ count );
298313 }
299314
300315 if ($ type === 'array ' ) { # array or nested arrays
301- return 'array_map(function () use ($faker, $uniqueFaker) {
302- return ' . $ this ->{__FUNCTION__ }($ items ) . ';
303- }, range(1, ' . $ count . ')) ' ;
316+ return $ this ->{__FUNCTION__ }($ items );
304317 }
305318
306319 if ($ type === 'object ' ) {
@@ -321,13 +334,16 @@ private function fakeForArray(SpecObjectInterface $property, int $count = 4): st
321334 /**
322335 * @param $items Schema|Reference|null
323336 * @param $count int
337+ * @param bool $nested
324338 * @return string
325- * @throws \cebe\openapi\exceptions\UnresolvableReferenceException
326- * @throws \yii\base\InvalidConfigException
327- * @throws exceptions\InvalidDefinitionException
339+ * @throws ExceptionInterface
340+ * @throws InvalidConfigException
341+ * @throws InvalidDefinitionException
342+ * @throws TypeErrorException
343+ * @throws UnresolvableReferenceException
328344 * @internal
329345 */
330- public function handleObject ($ items , $ count , $ nested = false ): string
346+ public function handleObject (Schema $ items , int $ count , bool $ nested = false ): string
331347 {
332348 $ props = '[ ' . PHP_EOL ;
333349 $ cs = new ComponentSchema ($ items , 'unnamed ' );
@@ -361,53 +377,32 @@ public function handleObject($items, $count, $nested = false): string
361377 * @param $items
362378 * @param $count
363379 * @return string
380+ * @throws ExceptionInterface
381+ * @throws InvalidConfigException
382+ * @throws InvalidDefinitionException
383+ * @throws TypeErrorException
384+ * @throws UnresolvableReferenceException
364385 * @internal
365386 */
366387 public function handleOneOf ($ items , $ count ): string
367388 {
368- $ fakerForADataType = [];
369389 $ result = 'array_map(function () use ($faker, $uniqueFaker) { ' ;
370390 foreach ($ items ->oneOf as $ key => $ aDataType ) {
371391 /** @var Schema|Reference $aDataType */
372- // $fakerForADataType[] = $this->{__FUNCTION__}($aDataType);
392+
373393 $ a1 = $ this ->fakeForArray ($ aDataType , 1 );
374394 $ result .= '$dataType ' . $ key . ' = ' . $ a1 . '; ' ;
375395 }
376396 $ ct = count ($ items ->oneOf ) - 1 ;
377397 $ result .= 'return ${"dataType".rand(0, ' . $ ct . ')}; ' ;
378- // $items = $items->oneOf[$rand];
379-
380- // $dataType'..'
381- // return "";
382398 $ result .= '}, range(1, ' . $ count . ')) ' ;
383399 return $ result ;
384400 }
385401
386- public function aString ()
387- {
388- }
389-
390- public function aNumber ()
391- {
392- }
393-
394- public function aInteger ()
395- {
396- }
397-
398- public function aBoolean ()
399- {
400- }
401-
402- public function aArray ()
403- {
404- }
405-
406- public function aObject ()
407- {
408- }
409-
410- public function aRefObj ()
402+ public function wrapAsArray ($ aElementFaker , $ uniqueItems , $ count ): string
411403 {
404+ return 'array_map(function () use ($faker, $uniqueFaker) {
405+ return ' . ($ uniqueItems ? str_replace ('$faker-> ' , '$uniqueFaker-> ' , $ aElementFaker ) : $ aElementFaker ) . ';
406+ }, range(1, ' . $ count . ')) ' ;
412407 }
413408}
0 commit comments