Skip to content

Commit b8c1546

Browse files
authored
Merge pull request #1 from cebe/master
Import changes from cebe/yii2-openapi
2 parents a5cb8fa + ee41f41 commit b8c1546

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1574
-29
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ Such values are not allowed:
182182
- `int null default null after low_price` (null and default will be handled by `nullable` and `default` keys respectively)
183183
- MEDIUMINT(10) UNSIGNED ZEROFILL NULL DEFAULT '7' COMMENT 'comment' AFTER `seti`, ADD INDEX `t` (`w`)
184184

185+
If `enum` and `x-db-type` both are provided then for database column schema (migrations), only `x-db-type` will be considered ignoring `enum`.
186+
185187
### `x-indexes`
186188

187189
Specify table indexes
@@ -446,6 +448,8 @@ It works on all 3 DB: MySQL, MariaDb and PgSQL.
446448

447449
Note: Changes in enum values are not very simple. For Mysql and Mariadb, migrations will be generated but in many cases custom modification in it are required. For Pgsql migrations for change in enum values will not be generated. It should be handled manually.
448450

451+
It will be ignored for database column schema (migrations) if `x-db-type` is provided.
452+
449453
## Handling of `numeric` (#numeric, #MariaDb)
450454

451455
precision-default = 10

src/lib/ValidationRulesBuilder.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ private function addRulesByAttributeName(Attribute $attribute):void
142142
'~(url|site|website|href|link)~i' => 'url',
143143
];
144144
foreach ($patterns as $pattern => $validator) {
145-
if (preg_match($pattern, strtolower($attribute->columnName))) {
145+
if (empty($attribute->reference) # ignore column name based rules in case of reference/relation # https://github.com/cebe/yii2-openapi/issues/159
146+
&& preg_match($pattern, strtolower($attribute->columnName))) {
146147
$key = $attribute->columnName . '_' . $validator;
147148
$this->rules[$key] = new ValidationRule([$attribute->columnName], $validator);
148149
return;
@@ -232,7 +233,9 @@ private function prepareTypeScope():void
232233
$this->typeScope['required'][$attribute->columnName] = $attribute->columnName;
233234
}
234235

235-
if ($attribute->phpType === 'string') {
236+
if ($attribute->phpType === 'string' &&
237+
empty($attribute->enumValues) # don't apply trim on enum columns # https://github.com/cebe/yii2-openapi/issues/158
238+
) {
236239
$this->typeScope['trim'][$attribute->columnName] = $attribute->columnName;
237240
}
238241

src/lib/openapi/ResponseSchema.php

+32-22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace cebe\yii2openapi\lib\openapi;
99

10+
use cebe\openapi\exceptions\UnresolvableReferenceException;
1011
use cebe\openapi\spec\MediaType;
1112
use cebe\openapi\spec\Operation;
1213
use cebe\openapi\spec\Reference;
@@ -36,10 +37,10 @@ protected static function isObjectSchema($schema): bool
3637
protected static function isArraySchemaWithRefItems($schema): bool
3738
{
3839
return isset($schema->items) && $schema->items instanceof Reference &&
39-
(isset($schema->type) && $schema->type === 'array');
40+
(isset($schema->type) && $schema->type === 'array');
4041
}
4142

42-
protected static function hasAttributesReference($schema):bool
43+
protected static function hasAttributesReference($schema): bool
4344
{
4445
return isset($schema->properties['attributes']) && $schema->properties['attributes'] instanceof Reference;
4546
}
@@ -49,17 +50,20 @@ protected static function schemaNameByRef($schemaOrReference): ?string
4950
// if($schemaOrReference instanceof Reference){
5051
// $schemaOrReference->resolve();
5152
// }
53+
if (!$schemaOrReference instanceof Reference) { # https://github.com/cebe/yii2-openapi/issues/175
54+
return null;
55+
}
5256
$ref = $schemaOrReference->getJsonReference()->getJsonPointer()->getPointer();
5357
$name = strpos($ref, '/components/schemas/') === 0 ? substr($ref, 20) : null;
5458
return str_replace(JunctionSchemas::PREFIX, '', $name);
5559
}
5660

5761
/**
58-
* @param \cebe\openapi\spec\Operation $operation
62+
* @param Operation $operation
5963
* @return array
60-
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
64+
* @throws UnresolvableReferenceException
6165
*/
62-
public static function guessResponseRelations(Operation $operation):array
66+
public static function guessResponseRelations(Operation $operation): array
6367
{
6468
if (!isset($operation->responses)) {
6569
return [];
@@ -109,12 +113,12 @@ public static function guessResponseRelations(Operation $operation):array
109113
}
110114

111115
/**
112-
* @param \cebe\openapi\spec\Operation $operation
116+
* @param Operation $operation
113117
* @param $actionType
114118
* @return string|null
115-
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
119+
* @throws UnresolvableReferenceException
116120
*/
117-
public static function guessModelClass(Operation $operation, $actionType):?string
121+
public static function guessModelClass(Operation $operation, $actionType): ?string
118122
{
119123
// first, check request body
120124
$requestBody = $operation->requestBody;
@@ -159,20 +163,26 @@ public static function guessModelClass(Operation $operation, $actionType):?strin
159163
}
160164

161165
/**
162-
* @param \cebe\openapi\SpecObjectInterface $property
166+
* @param SpecObjectInterface $property
163167
* @return array|null[]
164-
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
168+
* @throws UnresolvableReferenceException
165169
*/
166170
public static function guessModelClassFromJsonResource(SpecObjectInterface $property): array
167171
{
168-
$schema = $property instanceof Reference? $property->resolve() : $property;
169-
170-
if (self::isObjectSchema($schema) && self::hasAttributesReference($schema)) {
171-
$name = self::schemaNameByRef($schema->properties['attributes']);
172-
if ($name !== null) {
173-
return [$name, '', '', 'object'];
172+
$schema = $property instanceof Reference ? $property->resolve() : $property;
173+
if (self::isObjectSchema($schema)) {
174+
if (self::hasAttributesReference($schema)) {
175+
$name = self::schemaNameByRef($schema->properties['attributes']);
176+
if ($name !== null) {
177+
return [$name, '', '', 'object'];
178+
}
179+
return [null, null, null, null];
180+
} else { # https://github.com/cebe/yii2-openapi/issues/172
181+
$name = self::schemaNameByRef($property);
182+
if ($name !== null) {
183+
return [$name, '', '', 'object'];
184+
}
174185
}
175-
return [null, null, null, null];
176186
}
177187
if (self::isArraySchemaWithRefItems($property)) {
178188
$ref = $property->items->resolve();
@@ -188,11 +198,11 @@ public static function guessModelClassFromJsonResource(SpecObjectInterface $prop
188198
}
189199

190200
/**
191-
* @param \cebe\openapi\spec\MediaType $content
201+
* @param MediaType $content
192202
* @return array|null[]
193-
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
203+
* @throws UnresolvableReferenceException
194204
*/
195-
public static function guessModelClassFromContent(MediaType $content):array
205+
public static function guessModelClassFromContent(MediaType $content): array
196206
{
197207
/** @var $referencedSchema Schema */
198208
if ($content->schema instanceof Reference) {
@@ -255,9 +265,9 @@ public static function guessModelClassFromContent(MediaType $content):array
255265
* @param Operation $operation
256266
* @param $modelClass
257267
* @return null|array
258-
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
268+
* @throws UnresolvableReferenceException
259269
*/
260-
public static function findResponseWrapper(Operation $operation, $modelClass):?array
270+
public static function findResponseWrapper(Operation $operation, $modelClass): ?array
261271
{
262272
if (!isset($operation->responses)) {
263273
return null;

tests/specs/blog_v2/models/base/Post.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static function tableName()
2929
public function rules()
3030
{
3131
return [
32-
'trim' => [['title', 'slug', 'lang', 'created_at'], 'trim'],
32+
'trim' => [['title', 'slug', 'created_at'], 'trim'],
3333
'required' => [['title', 'category_id', 'active'], 'required'],
3434
'category_id_integer' => [['category_id'], 'integer'],
3535
'category_id_exist' => [['category_id'], 'exist', 'targetRelation' => 'Category'],

tests/specs/blog_v2/models/base/Tag.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static function tableName()
2121
public function rules()
2222
{
2323
return [
24-
'trim' => [['name', 'lang'], 'trim'],
24+
'trim' => [['name'], 'trim'],
2525
'required' => [['name', 'lang'], 'required'],
2626
'name_unique' => [['name'], 'unique'],
2727
'name_string' => [['name'], 'string', 'max' => 100],

tests/specs/blog_v2/models/base/User.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static function tableName()
2424
public function rules()
2525
{
2626
return [
27-
'trim' => [['login', 'email', 'password', 'role', 'created_at'], 'trim'],
27+
'trim' => [['login', 'email', 'password', 'created_at'], 'trim'],
2828
'required' => [['login', 'email', 'password'], 'required'],
2929
'login_unique' => [['login'], 'unique'],
3030
'email_unique' => [['email'], 'unique'],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
return [
4+
'openApiPath' => '@specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.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+
];
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
openapi: 3.0.3
3+
4+
info:
5+
title: 'Proxy-Service'
6+
version: 1.0.0
7+
8+
components:
9+
10+
schemas:
11+
12+
Mailing:
13+
description: Mailing
14+
type: object
15+
required:
16+
- id
17+
- name
18+
properties:
19+
id:
20+
type: integer
21+
readOnly: true
22+
name:
23+
description: name
24+
type: string
25+
maxLength: 128
26+
paymentMethodName:
27+
type: string
28+
enum:
29+
- card
30+
- cash
31+
- ewallet
32+
33+
paths:
34+
'/':
35+
get:
36+
operationId: opId
37+
summary: summary
38+
responses:
39+
'200':
40+
description: OK
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+
}

0 commit comments

Comments
 (0)