Skip to content

Commit 9bff78d

Browse files
committed
improved evaluating references and guessing model from referenced schema
1 parent dfe7892 commit 9bff78d

File tree

8 files changed

+258
-27
lines changed

8 files changed

+258
-27
lines changed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ REST API application generator for Yii2, openapi 3.0 YAML -> Yii2.
44

55
Base on [Gii, the Yii Framework Code Generator](https://www.yiiframework.com/extension/yiisoft/yii2-gii).
66

7-
[![Total Downloads](https://poser.pugx.org/phpunit/phpunit/downloads)](https://packagist.org/packages/phpunit/phpunit)
8-
97
[![Latest Stable Version](https://poser.pugx.org/cebe/yii2-openapi/v/stable)](https://packagist.org/packages/cebe/yii2-openapi)
108
[![Total Downloads](https://poser.pugx.org/cebe/yii2-openapi/downloads)](https://packagist.org/packages/cebe/yii2-openapi)
119
[![License](https://poser.pugx.org/cebe/yii2-openapi/license)](https://packagist.org/packages/cebe/yii2-openapi)

src/generator/ApiGenerator.php

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ protected function generateUrls()
396396
'route' => "$controller/$a$action",
397397
'actionParams' => $actionParams,
398398
'openApiOperation' => $operation,
399-
'modelClass' => $this->modelNamespace . '\\' . $modelClass,
399+
'modelClass' => $modelClass !== null ? $this->modelNamespace . '\\' . $modelClass : null,
400400
'responseWrapper' => $responseWrapper,
401401
];
402402
}
@@ -464,16 +464,16 @@ private function guessModelClassFromContent(MediaType $content)
464464
$referencedSchema = $content->schema->resolve();
465465
// Model data is directly returned
466466
if ($referencedSchema->type === null || $referencedSchema->type === 'object') {
467-
$ref = $content->schema->getReference();
468-
if (strpos($ref, '#/components/schemas/') === 0) {
469-
return [substr($ref, 21), '', ''];
467+
$ref = $content->schema->getJsonReference()->getJsonPointer()->getPointer();
468+
if (strpos($ref, '/components/schemas/') === 0) {
469+
return [substr($ref, 20), '', ''];
470470
}
471471
}
472472
// an array of Model data is directly returned
473473
if ($referencedSchema->type === 'array' && $referencedSchema->items instanceof Reference) {
474-
$ref = $referencedSchema->items->getReference();
475-
if (strpos($ref, '#/components/schemas/') === 0) {
476-
return [substr($ref, 21), '', ''];
474+
$ref = $referencedSchema->items->getJsonReference()->getJsonPointer()->getPointer();
475+
if (strpos($ref, '/components/schemas/') === 0) {
476+
return [substr($ref, 20), '', ''];
477477
}
478478
}
479479
} else {
@@ -488,26 +488,32 @@ private function guessModelClassFromContent(MediaType $content)
488488
$referencedModelSchema = $property->resolve();
489489
if ($referencedModelSchema->type === null || $referencedModelSchema->type === 'object') {
490490
// Model data is wrapped
491-
$ref = $property->getReference();
492-
if (strpos($ref, '#/components/schemas/') === 0) {
493-
return [substr($ref, 21), $propertyName, null];
491+
$ref = $property->getJsonReference()->getJsonPointer()->getPointer();
492+
if (strpos($ref, '/components/schemas/') === 0) {
493+
return [substr($ref, 20), $propertyName, null];
494494
}
495495
} elseif ($referencedModelSchema->type === 'array' && $referencedModelSchema->items instanceof Reference) {
496496
// an array of Model data is wrapped
497-
$ref = $referencedModelSchema->items->getReference();
498-
if (strpos($ref, '#/components/schemas/') === 0) {
499-
return [substr($ref, 21), null, $propertyName];
497+
$ref = $referencedModelSchema->items->getJsonReference()->getJsonPointer()->getPointer();
498+
if (strpos($ref, '/components/schemas/') === 0) {
499+
return [substr($ref, 20), null, $propertyName];
500500
}
501501
}
502502
} elseif ($property->type === 'array' && $property->items instanceof Reference) {
503503
// an array of Model data is wrapped
504-
$ref = $property->items->getReference();
505-
if (strpos($ref, '#/components/schemas/') === 0) {
506-
return [substr($ref, 21), null, $propertyName];
504+
$ref = $property->items->getJsonReference()->getJsonPointer()->getPointer();
505+
if (strpos($ref, '/components/schemas/') === 0) {
506+
return [substr($ref, 20), null, $propertyName];
507507
}
508508
}
509509
}
510510
}
511+
if ($referencedSchema->type === 'array' && $referencedSchema->items instanceof Reference) {
512+
$ref = $referencedSchema->items->getJsonReference()->getJsonPointer()->getPointer();
513+
if (strpos($ref, '/components/schemas/') === 0) {
514+
return [substr($ref, 20), '', ''];
515+
}
516+
}
511517
return [null, null, null];
512518
}
513519

@@ -588,13 +594,13 @@ protected function generateModels()
588594

589595
foreach ($schema->properties as $name => $property) {
590596
if ($property instanceof Reference) {
591-
$ref = $property->getReference();
597+
$ref = $property->getJsonReference()->getJsonPointer()->getPointer();
592598
$resolvedProperty = $property->resolve();
593599
$dbName = "{$name}_id";
594600
$dbType = 'integer'; // for a foreign key
595-
if (strpos($ref, '#/components/schemas/') === 0) {
601+
if (strpos($ref, '/components/schemas/') === 0) {
596602
// relation
597-
$type = substr($ref, 21);
603+
$type = substr($ref, 20);
598604
$relations[$name] = [
599605
'class' => $type,
600606
'method' => 'hasOne',
@@ -777,9 +783,9 @@ protected function getSchemaType($schema)
777783
return 'float';
778784
case 'array':
779785
if (isset($schema->items) && $schema->items instanceof Reference) {
780-
$ref = $schema->items->getReference();
781-
if (strpos($ref, '#/components/schemas/') === 0) {
782-
return [substr($ref, 21) . '[]', substr($ref, 21)];
786+
$ref = $schema->items->getJsonReference()->getJsonPointer()->getPointer();
787+
if (strpos($ref, '/components/schemas/') === 0) {
788+
return [substr($ref, 20) . '[]', substr($ref, 20)];
783789
}
784790
}
785791
// no break here
@@ -813,9 +819,9 @@ protected function getDbType($name, $schema)
813819
// case 'array':
814820
// TODO array might refer to has_many relation
815821
// if (isset($schema->items) && $schema->items instanceof Reference) {
816-
// $ref = $schema->items->getReference();
817-
// if (strpos($ref, '#/components/schemas/') === 0) {
818-
// return substr($ref, 21) . '[]';
822+
// $ref = $schema->items->getJsonReference()->getJsonPointer()->getPointer();
823+
// if (strpos($ref, '/components/schemas/') === 0) {
824+
// return substr($ref, 20) . '[]';
819825
// }
820826
// }
821827
// // no break here

tests/specs/petstore_arrayref.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
return [
4+
'openApiPath' => '@specs/petstore_arrayref.yaml',
5+
'generateUrls' => true,
6+
'generateModels' => true,
7+
'excludeModels' => [
8+
'Error',
9+
],
10+
'generateControllers' => true,
11+
'generateMigrations' => false, // TODO add tests for migrations
12+
];

tests/specs/petstore_arrayref.yaml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
openapi: "3.0.0"
2+
info:
3+
version: 1.0.0
4+
title: Swagger Petstore
5+
license:
6+
name: MIT
7+
servers:
8+
- url: http://petstore.swagger.io/v1
9+
paths:
10+
/pets:
11+
get:
12+
summary: List all pets
13+
operationId: listPets
14+
tags:
15+
- pets
16+
parameters:
17+
- name: limit
18+
in: query
19+
description: How many items to return at one time (max 100)
20+
required: false
21+
schema:
22+
type: integer
23+
format: int32
24+
responses:
25+
'200':
26+
description: A paged array of pets
27+
headers:
28+
x-next:
29+
description: A link to the next page of responses
30+
schema:
31+
type: string
32+
content:
33+
application/json:
34+
schema:
35+
$ref: "#/components/schemas/Pets"
36+
default:
37+
description: unexpected error
38+
content:
39+
application/json:
40+
schema:
41+
$ref: "#/components/schemas/Error"
42+
post:
43+
summary: Create a pet
44+
operationId: createPets
45+
tags:
46+
- pets
47+
responses:
48+
'201':
49+
description: Null response
50+
default:
51+
description: unexpected error
52+
content:
53+
application/json:
54+
schema:
55+
$ref: "#/components/schemas/Error"
56+
/pets/{petId}:
57+
get:
58+
summary: Info for a specific pet
59+
operationId: showPetById
60+
tags:
61+
- pets
62+
parameters:
63+
- name: petId
64+
in: path
65+
required: true
66+
description: The id of the pet to retrieve
67+
schema:
68+
type: string
69+
responses:
70+
'200':
71+
$ref: "#/components/responses/Pets"
72+
default:
73+
description: unexpected error
74+
content:
75+
application/json:
76+
schema:
77+
$ref: "#/components/schemas/Error"
78+
components:
79+
schemas:
80+
Pet:
81+
description: A Pet
82+
required:
83+
- id
84+
- name
85+
properties:
86+
id:
87+
type: integer
88+
format: int64
89+
name:
90+
type: string
91+
tag:
92+
type: string
93+
x-faker: "$faker->randomElement(['one', 'two', 'three', 'four'])"
94+
Pets:
95+
type: array
96+
items:
97+
$ref: "#/components/schemas/Pet"
98+
Error:
99+
required:
100+
- code
101+
- message
102+
properties:
103+
code:
104+
type: integer
105+
format: int32
106+
message:
107+
type: string
108+
responses:
109+
Pets:
110+
description: Expected response to a valid request
111+
content:
112+
application/json:
113+
schema:
114+
type: array
115+
items:
116+
$ref: "#/components/schemas/Pet"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
/**
3+
* OpenAPI UrlRules
4+
*
5+
* This file is auto generated.
6+
*/
7+
return array (
8+
'GET pets' => 'pet/index',
9+
'POST pets' => 'pet/create',
10+
'GET pets/<petId>' => 'pet/view',
11+
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace app\controllers;
4+
5+
class PetController extends \yii\rest\Controller
6+
{
7+
public function actions()
8+
{
9+
return [
10+
'index' => [
11+
'class' => \yii\rest\IndexAction::class,
12+
'modelClass' => \app\models\Pet::class,
13+
'checkAccess' => [$this, 'checkAccess'],
14+
],
15+
'create' => [
16+
'class' => \yii\rest\CreateAction::class,
17+
'modelClass' => \app\models\Pet::class,
18+
'checkAccess' => [$this, 'checkAccess'],
19+
],
20+
'view' => [
21+
'class' => \yii\rest\ViewAction::class,
22+
'modelClass' => \app\models\Pet::class,
23+
'checkAccess' => [$this, 'checkAccess'],
24+
],
25+
'options' => [
26+
'class' => \yii\rest\OptionsAction::class,
27+
],
28+
];
29+
}
30+
31+
/**
32+
* Checks the privilege of the current user.
33+
*
34+
* This method checks whether the current user has the privilege
35+
* to run the specified action against the specified data model.
36+
* If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
37+
*
38+
* @param string $action the ID of the action to be executed
39+
* @param object $model the model to be accessed. If null, it means no specific model is being accessed.
40+
* @param array $params additional parameters
41+
* @throws \yii\web\ForbiddenHttpException if the user does not have access
42+
*/
43+
public function checkAccess($action, $model = null, $params = [])
44+
{
45+
// TODO implement checkAccess
46+
}
47+
48+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace app\models;
4+
5+
/**
6+
* A Pet
7+
*
8+
* @property int $id
9+
* @property string $name
10+
* @property string $tag
11+
*/
12+
class Pet extends \yii\db\ActiveRecord
13+
{
14+
public static function tableName()
15+
{
16+
return '{{%pets}}';
17+
}
18+
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace app\models;
4+
5+
use Faker\Factory as FakerFactory;
6+
7+
/**
8+
* Fake data generator for Pet
9+
*/
10+
class PetFaker
11+
{
12+
public function generateModel()
13+
{
14+
$faker = FakerFactory::create(\Yii::$app->language);
15+
$model = new Pet;
16+
$model->id = $faker->numberBetween(0, PHP_INT_MAX);
17+
$model->name = $faker->sentence;
18+
$model->tag = $faker->randomElement(['one', 'two', 'three', 'four']);
19+
return $model;
20+
}
21+
}

0 commit comments

Comments
 (0)