Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Commit 1d168f9

Browse files
authored
Merge pull request #28 from SOHELAHMED7/153-nullable-false-should-put-attribute-in-required-section-in-model-validation-rules
Resolve: nullable false should put attribute in required section in model validation rules
2 parents eeea676 + 1da94f0 commit 1d168f9

File tree

24 files changed

+132
-19
lines changed

24 files changed

+132
-19
lines changed

src/lib/AttributeResolver.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,17 @@ public function resolve():DbModel
9898
/** @var $property \cebe\yii2openapi\lib\openapi\PropertySchema */
9999

100100
$isRequired = $this->schema->isRequiredProperty($property->getName());
101+
$nullableValue = $property->getProperty()->getSerializableData()->nullable ?? null;
102+
if ($nullableValue === false) { // see docs in README regarding NOT NULL, required and nullable
103+
$isRequired = true;
104+
}
105+
101106
if ($this->isJunctionSchema) {
102107
$this->resolveJunctionTableProperty($property, $isRequired);
103108
} elseif ($this->hasMany2Many) {
104109
$this->resolveHasMany2ManyTableProperty($property, $isRequired);
105110
} else {
106-
$this->resolveProperty($property, $isRequired);
111+
$this->resolveProperty($property, $isRequired, $nullableValue);
107112
}
108113
}
109114
return Yii::createObject(DbModel::class, [
@@ -202,19 +207,26 @@ protected function resolveHasMany2ManyTableProperty(PropertySchema $property, bo
202207
/**
203208
* @param \cebe\yii2openapi\lib\openapi\PropertySchema $property
204209
* @param bool $isRequired
210+
* @param bool|null|string $nullableValue if string then its value will be only constant `ARG_ABSENT`. Default `null` is avoided because it can be in passed value in method call
205211
* @throws \cebe\yii2openapi\lib\exceptions\InvalidDefinitionException
206212
* @throws \yii\base\InvalidConfigException
207213
*/
208-
protected function resolveProperty(PropertySchema $property, bool $isRequired):void
209-
{
214+
protected function resolveProperty(
215+
PropertySchema $property,
216+
bool $isRequired,
217+
$nullableValue = 'ARG_ABSENT'
218+
):void {
219+
if ($nullableValue === 'ARG_ABSENT') {
220+
$nullableValue = $property->getProperty()->getSerializableData()->nullable ?? null;
221+
}
210222
$attribute = Yii::createObject(Attribute::class, [$property->getName()]);
211223
$attribute->setRequired($isRequired)
212224
->setDescription($property->getAttr('description', ''))
213225
->setReadOnly($property->isReadonly())
214226
->setDefault($property->guessDefault())
215227
->setXDbType($property->getAttr(CustomSpecAttr::DB_TYPE))
216228
->setXDbDefaultExpression($property->getAttr(CustomSpecAttr::DB_DEFAULT_EXPRESSION))
217-
->setNullable($property->getProperty()->getSerializableData()->nullable ?? null)
229+
->setNullable($nullableValue)
218230
->setIsPrimary($property->isPrimaryKey())
219231
->setForeignKeyColumnName($property->fkColName);
220232
if ($property->isReference()) {

src/lib/FakerStubResolver.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ private function fakeForFloat(?int $min, ?int $max):?string
212212

213213
private function fakeForArray():string
214214
{
215+
if ($this->attribute->required) {
216+
return '["a" => "b"]';
217+
}
215218
return '[]';
216219
}
217220
}

src/lib/ValidationRulesBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ private function addNumericRule(Attribute $attribute):void
218218
private function prepareTypeScope():void
219219
{
220220
foreach ($this->model->attributes as $attribute) {
221+
/** @var $attribute \cebe\yii2openapi\lib\items\Attribute */
221222
if ($attribute->isReadOnly()) {
222223
continue;
223224
}
@@ -227,7 +228,7 @@ private function prepareTypeScope():void
227228
) {
228229
continue;
229230
}
230-
if ($attribute->defaultValue === null && $attribute->isRequired()) {
231+
if (/*$attribute->defaultValue === null &&*/ $attribute->isRequired()) {
231232
$this->typeScope['required'][$attribute->columnName] = $attribute->columnName;
232233
}
233234

src/lib/openapi/ComponentSchema.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ class ComponentSchema
3939
*/
4040
private $pkName;
4141

42-
/**@var array* */
42+
/** @var array* */
4343
private $requiredProps;
4444

45-
/**@var array* */
45+
/** @var array* */
4646
private $indexes;
4747

4848
/**

tests/fixtures/blog.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
->setDescription('The User')
118118
->setFakerStub('$faker->randomElement(\User::find()->select("id")->column())'),
119119
'message' => (new Attribute('message', ['phpType' => 'array', 'dbType' => 'json', 'xDbType' => 'json']))
120-
->setRequired()->setDefault([])->setFakerStub('[]'),
120+
->setRequired()->setDefault([])->setFakerStub('["a" => "b"]'),
121121
'meta_data' => (new Attribute('meta_data', ['phpType' => 'array', 'dbType' => 'json', 'xDbType' => 'json']))
122122
->setDefault([])->setFakerStub('[]'),
123123
'created_at' => (new Attribute('created_at',['phpType' => 'int', 'dbType' => 'integer']))

tests/specs/blog/models/CommentFaker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function generateModel($attributes = [])
3232
//$model->id = $uniqueFaker->numberBetween(0, 1000000);
3333
$model->post_id = $faker->randomElement(\app\models\Post::find()->select("id")->column());
3434
$model->author_id = $faker->randomElement(\app\models\User::find()->select("id")->column());
35-
$model->message = [];
35+
$model->message = ["a" => "b"];
3636
$model->meta_data = [];
3737
$model->created_at = $faker->unixTime;
3838
if (!is_callable($attributes)) {

tests/specs/blog/models/base/Category.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function rules()
2222
{
2323
return [
2424
'trim' => [['title'], 'trim'],
25-
'required' => [['title'], 'required'],
25+
'required' => [['title', 'active'], 'required'],
2626
'title_unique' => [['title'], 'unique'],
2727
'title_string' => [['title'], 'string', 'max' => 255],
2828
'active_boolean' => [['active'], 'boolean'],

tests/specs/blog/models/base/Comment.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function rules()
2626
{
2727
return [
2828
'trim' => [['post_id'], 'trim'],
29-
'required' => [['post_id', 'author_id', 'created_at'], 'required'],
29+
'required' => [['post_id', 'author_id', 'message', 'created_at'], 'required'],
3030
'post_id_string' => [['post_id'], 'string', 'max' => 128],
3131
'post_id_exist' => [['post_id'], 'exist', 'targetRelation' => 'Post'],
3232
'author_id_integer' => [['author_id'], 'integer'],

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function rules()
2828
{
2929
return [
3030
'trim' => [['title', 'slug', 'created_at'], 'trim'],
31-
'required' => [['title', 'category_id'], 'required'],
31+
'required' => [['title', 'category_id', 'active'], 'required'],
3232
'category_id_integer' => [['category_id'], 'integer'],
3333
'category_id_exist' => [['category_id'], 'exist', 'targetRelation' => 'Category'],
3434
'created_by_id_integer' => [['created_by_id'], 'integer'],
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/153_nullable_false_in_required/153_nullable_false_in_required.yaml',
5+
'generateUrls' => false,
6+
'generateModels' => true,
7+
'excludeModels' => [
8+
'Error',
9+
],
10+
'generateControllers' => false,
11+
'generateMigrations' => false,
12+
'generateModelFaker' => false,
13+
];
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
openapi: "3.0.0"
2+
info:
3+
version: 1.0.0
4+
title: 153_nullable_false_in_required \#153
5+
paths:
6+
/:
7+
get:
8+
summary: List
9+
operationId: list
10+
responses:
11+
'200':
12+
description: The information
13+
14+
components:
15+
schemas:
16+
Pristine:
17+
type: object
18+
description: 153_nullable_false_in_required
19+
required:
20+
- id
21+
properties:
22+
id:
23+
type: integer
24+
billing_factor:
25+
description: integer between 0 and 100, default value 100
26+
type: integer
27+
default: 100
28+
nullable: false
29+
x-faker: '$faker->numberBetween(0, 100)'
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 Pristine extends \app\models\base\Pristine
6+
{
7+
8+
9+
}
10+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace app\models\base;
4+
5+
/**
6+
* 153_nullable_false_in_required
7+
*
8+
* @property int $id
9+
* @property int $billing_factor integer between 0 and 100, default value 100
10+
*
11+
*/
12+
abstract class Pristine extends \yii\db\ActiveRecord
13+
{
14+
public static function tableName()
15+
{
16+
return '{{%pristines}}';
17+
}
18+
19+
public function rules()
20+
{
21+
return [
22+
'required' => [['billing_factor'], 'required'],
23+
'billing_factor_integer' => [['billing_factor'], 'integer'],
24+
'billing_factor_default' => [['billing_factor'], 'default', 'value' => 100],
25+
];
26+
}
27+
}

tests/specs/x_db_type/rules_and_more/maria/app/models/mariafaker/EditcolumnFaker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function generateModel($attributes = [])
3838
$model->dec_col = $faker->randomFloat();
3939
$model->str_col_def = substr($faker->word(3), 0, 3);
4040
$model->json_col = $faker->sentence;
41-
$model->json_col_2 = [];
41+
$model->json_col_2 = ["a" => "b"];
4242
$model->numeric_col = $faker->randomFloat();
4343
$model->json_col_def_n = [];
4444
$model->json_col_def_n_2 = [];

tests/specs/x_db_type/rules_and_more/maria/app/models/mariamodel/base/Alldbdatatype.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function rules()
6262
{
6363
return [
6464
'trim' => [['string_col', 'varchar_col', 'text_col', 'varchar_4_col', 'char_4_col', 'char_5_col', 'char_6_col', 'char_7_col', 'char_8_col', 'date_col', 'time_col', 'datetime_col', 'timestamp_col', 'year_col', 'text_def'], 'trim'],
65-
'required' => [['char_6_col'], 'required'],
65+
'required' => [['char_6_col', 'char_7_col'], 'required'],
6666
'string_col_string' => [['string_col'], 'string', 'max' => 255],
6767
'varchar_col_string' => [['varchar_col'], 'string', 'max' => 132],
6868
'text_col_string' => [['text_col'], 'string'],

tests/specs/x_db_type/rules_and_more/maria/app/models/mariamodel/base/Editcolumn.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function rules()
3030
{
3131
return [
3232
'trim' => [['name', 'tag', 'first_name', 'string_col', 'str_col_def', 'json_col'], 'trim'],
33+
'required' => [['name', 'str_col_def', 'json_col', 'json_col_2'], 'required'],
3334
'name_string' => [['name'], 'string', 'max' => 254],
3435
'name_default' => [['name'], 'default', 'value' => 'Horse-2'],
3536
'tag_string' => [['tag'], 'string'],

tests/specs/x_db_type/rules_and_more/mysql/app/models/EditcolumnFaker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function generateModel($attributes = [])
3737
$model->dec_col = $faker->randomFloat();
3838
$model->str_col_def = substr($faker->word(3), 0, 3);
3939
$model->json_col = $faker->sentence;
40-
$model->json_col_2 = [];
40+
$model->json_col_2 = ["a" => "b"];
4141
$model->numeric_col = $faker->randomFloat();
4242
$model->json_col_def_n = [];
4343
$model->json_col_def_n_2 = [];

tests/specs/x_db_type/rules_and_more/mysql/app/models/base/Alldbdatatype.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function rules()
6262
{
6363
return [
6464
'trim' => [['string_col', 'varchar_col', 'text_col', 'varchar_4_col', 'char_4_col', 'char_5_col', 'char_6_col', 'char_7_col', 'char_8_col', 'date_col', 'time_col', 'datetime_col', 'timestamp_col', 'year_col', 'text_def'], 'trim'],
65-
'required' => [['char_6_col'], 'required'],
65+
'required' => [['char_6_col', 'char_7_col'], 'required'],
6666
'string_col_string' => [['string_col'], 'string', 'max' => 255],
6767
'varchar_col_string' => [['varchar_col'], 'string', 'max' => 132],
6868
'text_col_string' => [['text_col'], 'string'],

tests/specs/x_db_type/rules_and_more/mysql/app/models/base/Editcolumn.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function rules()
3030
{
3131
return [
3232
'trim' => [['name', 'tag', 'first_name', 'string_col', 'str_col_def', 'json_col'], 'trim'],
33+
'required' => [['name', 'str_col_def', 'json_col', 'json_col_2'], 'required'],
3334
'name_string' => [['name'], 'string', 'max' => 254],
3435
'name_default' => [['name'], 'default', 'value' => 'Horse-2'],
3536
'tag_string' => [['tag'], 'string'],

tests/specs/x_db_type/rules_and_more/pgsql/app/models/pgsqlfaker/EditcolumnFaker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function generateModel($attributes = [])
3838
$model->dec_col = $faker->randomFloat();
3939
$model->str_col_def = $faker->sentence;
4040
$model->json_col = $faker->sentence;
41-
$model->json_col_2 = [];
41+
$model->json_col_2 = ["a" => "b"];
4242
$model->numeric_col = $faker->randomFloat();
4343
$model->json_col_def_n = [];
4444
$model->json_col_def_n_2 = [];

tests/specs/x_db_type/rules_and_more/pgsql/app/models/pgsqlmodel/base/Alldbdatatype.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function rules()
112112
{
113113
return [
114114
'trim' => [['string_col', 'varchar_col', 'text_col', 'varchar_4_col', 'varchar_5_col', 'char_4_col', 'char_5_col', 'char_6_col', 'char_7_col', 'char_8_col', 'date_col', 'time_col', 'time_col_2', 'time_col_3', 'time_col_4', 'timetz_col', 'timetz_col_2', 'timestamp_col', 'timestamp_col_2', 'timestamp_col_3', 'timestamp_col_4', 'timestamptz_col', 'timestamptz_col_2', 'date2', 'timestamp_col_z', 'box_col', 'character_col', 'character_n', 'character_varying', 'character_varying_n', 'text_def', 'cidr_col', 'circle_col', 'date_col_z', 'inet_col', 'interval_col', 'interval_col_2', 'interval_col_3', 'line_col', 'lseg_col', 'macaddr_col', 'money_col', 'path_col', 'point_col', 'polygon_col', 'tsquery_col', 'tsvector_col', 'txid_snapshot_col', 'uuid_col', 'xml_col'], 'trim'],
115-
'required' => [['char_6_col'], 'required'],
115+
'required' => [['char_6_col', 'char_7_col', 'smallserial_col', 'serial2_col', 'bigserial_col', 'bigserial_col_2', 'serial_col', 'serial4_col'], 'required'],
116116
'string_col_string' => [['string_col'], 'string'],
117117
'varchar_col_string' => [['varchar_col'], 'string'],
118118
'text_col_string' => [['text_col'], 'string'],

tests/specs/x_db_type/rules_and_more/pgsql/app/models/pgsqlmodel/base/Editcolumn.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function rules()
3131
{
3232
return [
3333
'trim' => [['name', 'tag', 'first_name', 'string_col', 'str_col_def', 'json_col'], 'trim'],
34+
'required' => [['name', 'str_col_def', 'json_col', 'json_col_2'], 'required'],
3435
'name_string' => [['name'], 'string', 'max' => 254],
3536
'name_default' => [['name'], 'default', 'value' => 'Horse-2'],
3637
'tag_string' => [['tag'], 'string'],

tests/unit/IssueFixTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,19 @@ private function deleteTablesForWrongMigrationForPgsqlForStringVarcharDatatype14
257257
{
258258
Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute();
259259
}
260+
261+
// https://github.com/cebe/yii2-openapi/issues/153
262+
// nullable false should put attribute in required section in model validation rules
263+
public function testNullableFalseInRequired()
264+
{
265+
$testFile = Yii::getAlias("@specs/issue_fix/153_nullable_false_in_required/153_nullable_false_in_required.php");
266+
$this->runGenerator($testFile, 'mysql');
267+
$actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [
268+
'recursive' => true,
269+
]);
270+
$expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/153_nullable_false_in_required/app"), [
271+
'recursive' => true,
272+
]);
273+
$this->checkFiles($actualFiles, $expectedFiles);
274+
}
260275
}

tests/unit/ValidatorRulesBuilderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public function testBuild()
4747
'contact_email',
4848
'required_with_def',
4949
], 'trim'),
50-
'required' => new ValidationRule(['title', 'category_id'], 'required'),
50+
'required' => new ValidationRule(['title', 'category_id', 'required_with_def'], 'required'),
5151
'category_id_integer' => new ValidationRule(['category_id'], 'integer'),
5252
'category_id_exist' => new ValidationRule(['category_id'], 'exist', ['targetRelation' => 'Category']),
5353
'title_active_unique' => new ValidationRule(['title', 'active'], 'unique', [

0 commit comments

Comments
 (0)