From f7c2b5b58f75f20bf50721ecc785465ad3e215c5 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Tue, 28 May 2024 14:18:53 +0530 Subject: [PATCH 01/15] Initial commit to create PR --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df87e47a..86e77ce8 100644 --- a/README.md +++ b/README.md @@ -564,3 +564,4 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). + From f41f0fa4eade6896fa25a0a546454ae4b111118d Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Tue, 28 May 2024 14:22:03 +0530 Subject: [PATCH 02/15] Undo initial commit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 86e77ce8..df87e47a 100644 --- a/README.md +++ b/README.md @@ -564,4 +564,3 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). - From 51875cb57d7fc8905c5acf7af892759968f4ce05 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Tue, 28 May 2024 14:34:20 +0530 Subject: [PATCH 03/15] Add docs for https://github.com/cebe/yii2-openapi/issues/173 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b04e500f..711b2a1c 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,8 @@ Such values are not allowed: - `int null default null after low_price` (null and default will be handled by `nullable` and `default` keys respectively) - MEDIUMINT(10) UNSIGNED ZEROFILL NULL DEFAULT '7' COMMENT 'comment' AFTER `seti`, ADD INDEX `t` (`w`) +If `enum` and `x-db-type` both are provided then for database column schema (migrations), only `x-db-type` will be considered ignoring `enum`. + ### `x-indexes` Specify table indexes @@ -446,6 +448,8 @@ It works on all 3 DB: MySQL, MariaDb and PgSQL. 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. +It will be ignored for database column schema (migrations) if `x-db-type` is provided. + ## Handling of `numeric` (#numeric, #MariaDb) precision-default = 10 From 949a32faaf719f1ac9e3fed0fc58905578a68cfa Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Tue, 28 May 2024 17:09:43 +0530 Subject: [PATCH 04/15] Fix https://github.com/cebe/yii2-openapi/issues/175 --- src/lib/openapi/ResponseSchema.php | 3 + .../index.php | 14 ++ .../index.yaml | 113 ++++++++++++++ .../pgsql/config/urls.rest.php | 10 ++ .../pgsql/controllers/AccountController.php | 20 +++ .../controllers/base/AccountController.php | 32 ++++ .../m200000_000000_create_table_accounts.php | 21 +++ .../m200000_000001_create_table_contacts.php | 24 +++ ...00_000002_create_table_payment_methods.php | 22 +++ .../pgsql/models/Account.php | 10 ++ .../pgsql/models/AccountFaker.php | 42 +++++ .../pgsql/models/BaseModelFaker.php | 144 ++++++++++++++++++ .../pgsql/models/Contact.php | 10 ++ .../pgsql/models/ContactFaker.php | 52 +++++++ .../pgsql/models/PaymentMethod.php | 10 ++ .../pgsql/models/PaymentMethodFaker.php | 40 +++++ .../pgsql/models/base/Account.php | 29 ++++ .../pgsql/models/base/Contact.php | 39 +++++ .../pgsql/models/base/PaymentMethod.php | 28 ++++ tests/unit/IssueFixTest.php | 15 ++ 20 files changed, 678 insertions(+) create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.yaml create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/config/urls.rest.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/controllers/AccountController.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/controllers/base/AccountController.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000000_create_table_accounts.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000001_create_table_contacts.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000002_create_table_payment_methods.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Account.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/AccountFaker.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/BaseModelFaker.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Contact.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/ContactFaker.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/PaymentMethod.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/PaymentMethodFaker.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Account.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Contact.php create mode 100644 tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/PaymentMethod.php diff --git a/src/lib/openapi/ResponseSchema.php b/src/lib/openapi/ResponseSchema.php index f64bd8de..a0274449 100644 --- a/src/lib/openapi/ResponseSchema.php +++ b/src/lib/openapi/ResponseSchema.php @@ -49,6 +49,9 @@ protected static function schemaNameByRef($schemaOrReference): ?string // if($schemaOrReference instanceof Reference){ // $schemaOrReference->resolve(); // } + if (!$schemaOrReference instanceof Reference) { # https://github.com/cebe/yii2-openapi/issues/175 + return null; + } $ref = $schemaOrReference->getJsonReference()->getJsonPointer()->getPointer(); $name = strpos($ref, '/components/schemas/') === 0 ? substr($ref, 20) : null; return str_replace(JunctionSchemas::PREFIX, '', $name); diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php new file mode 100644 index 00000000..3ccbc836 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php @@ -0,0 +1,14 @@ + '@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.yaml', + 'generateUrls' => true, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => true, + 'generateMigrations' => true, + 'generateModelFaker' => true, // `generateModels` must be `true` in orde to use `generateModelFaker` as `true` +]; + diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.yaml b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.yaml new file mode 100644 index 00000000..429b59ad --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.yaml @@ -0,0 +1,113 @@ + +openapi: 3.0.3 + +info: + title: 'Proxy-Service' + version: 1.0.0 + +components: + + responses: + + AccountExpanded: + description: 'Returns one account by ID with additional information.' + content: + application/vnd.api+json: + schema: + type: object + required: + - status + - Account + properties: + status: + type: string + enum: + - valid + - invalid + Account: + allOf: + - $ref: '#/components/schemas/Account' + - type: object + properties: + invoiceContact: + $ref: "#/components/schemas/Contact" + paymentMethod: + $ref: "#/components/schemas/PaymentMethod" + errors: + type: object + description: only exists if status = invalid + + schemas: + + Account: + description: Account + type: object + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + description: account name + type: string + maxLength: 128 + paymentMethodName: + type: string + + Contact: + description: Contact + type: object + required: + - id + - account + properties: + id: + type: integer + readOnly: true + account: + $ref: '#/components/schemas/Account' + active: + type: boolean + default: false + nickname: + type: string + + PaymentMethod: + type: object + description: PaymentMethod + x-indexes: + - 'unique:name' + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + type: string + example: Bank transfer within 14 days + maxLength: 150 + x-faker: false + +paths: + + '/account/{id}': + parameters: + - name: Id + in: path + description: ID of Account + required: true + schema: + type: integer + + get: + operationId: getAccount + summary: Account information + responses: + '200': + $ref: '#/components/responses/AccountExpanded' + '404': + description: Account with id = "\" was not found. diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/config/urls.rest.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/config/urls.rest.php new file mode 100644 index 00000000..d448d409 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/config/urls.rest.php @@ -0,0 +1,10 @@ +' => 'account/view', + 'account/' => 'account/options', +]; diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/controllers/AccountController.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/controllers/AccountController.php new file mode 100644 index 00000000..b4044b8f --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/controllers/AccountController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionView($id); + +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000000_create_table_accounts.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000000_create_table_accounts.php new file mode 100644 index 00000000..1606f2fc --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000000_create_table_accounts.php @@ -0,0 +1,21 @@ +createTable('{{%accounts}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->string(128)->notNull(), + 'paymentMethodName' => $this->text()->null(), + ]); + } + + public function down() + { + $this->dropTable('{{%accounts}}'); + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000001_create_table_contacts.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000001_create_table_contacts.php new file mode 100644 index 00000000..5fcda9dc --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000001_create_table_contacts.php @@ -0,0 +1,24 @@ +createTable('{{%contacts}}', [ + 'id' => $this->primaryKey(), + 'account_id' => $this->integer()->notNull(), + 'active' => $this->boolean()->null()->defaultValue(false), + 'nickname' => $this->text()->null(), + ]); + $this->addForeignKey('fk_contacts_account_id_accounts_id', '{{%contacts}}', 'account_id', '{{%accounts}}', 'id'); + } + + public function down() + { + $this->dropForeignKey('fk_contacts_account_id_accounts_id', '{{%contacts}}'); + $this->dropTable('{{%contacts}}'); + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000002_create_table_payment_methods.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000002_create_table_payment_methods.php new file mode 100644 index 00000000..b6be74a0 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/migrations_pgsql_db/m200000_000002_create_table_payment_methods.php @@ -0,0 +1,22 @@ +createTable('{{%payment_methods}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->string(150)->notNull(), + ]); + $this->createIndex('payment_methods_name_key', '{{%payment_methods}}', 'name', true); + } + + public function down() + { + $this->dropIndex('payment_methods_name_key', '{{%payment_methods}}'); + $this->dropTable('{{%payment_methods}}'); + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Account.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Account.php new file mode 100644 index 00000000..2d25d7fc --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Account.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Account(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = substr($faker->text(128), 0, 128); + $model->paymentMethodName = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/BaseModelFaker.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Contact.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Contact.php new file mode 100644 index 00000000..8447fdaf --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/Contact.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Contact(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->account_id = $faker->randomElement(\app\models\Account::find()->select("id")->column()); + $model->active = $faker->boolean; + $model->nickname = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } + + public static function dependentOn() + { + return [ + // just model class names + 'Account', + + ]; + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/PaymentMethod.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/PaymentMethod.php new file mode 100644 index 00000000..dec326f2 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/PaymentMethod.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new PaymentMethod(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Account.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Account.php new file mode 100644 index 00000000..f3dae5db --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Account.php @@ -0,0 +1,29 @@ + [['name', 'paymentMethodName'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string', 'max' => 128], + 'paymentMethodName_string' => [['paymentMethodName'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Contact.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Contact.php new file mode 100644 index 00000000..21a2e7f1 --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/Contact.php @@ -0,0 +1,39 @@ + [['nickname'], 'trim'], + 'required' => [['account_id'], 'required'], + 'account_id_integer' => [['account_id'], 'integer'], + 'account_id_exist' => [['account_id'], 'exist', 'targetRelation' => 'Account'], + 'active_boolean' => [['active'], 'boolean'], + 'active_default' => [['active'], 'default', 'value' => false], + 'nickname_string' => [['nickname'], 'string'], + ]; + } + + public function getAccount() + { + return $this->hasOne(\app\models\Account::class, ['id' => 'account_id']); + } +} diff --git a/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/PaymentMethod.php b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/PaymentMethod.php new file mode 100644 index 00000000..79e8c05b --- /dev/null +++ b/tests/specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql/models/base/PaymentMethod.php @@ -0,0 +1,28 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_unique' => [['name'], 'unique'], + 'name_string' => [['name'], 'string', 'max' => 150], + ]; + } +} diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index c38a57ff..04a31c2d 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -300,4 +300,19 @@ public function test163GeneratorCrashWhenUsingReferenceInsideAnObject() ]); $this->checkFiles($actualFiles, $expectedFiles); } + + // #175 https://github.com/cebe/yii2-openapi/issues/175 + // Bug: allOf with multiple $refs + public function test175BugAllOfWithMultipleDollarRefs() + { + $testFile = Yii::getAlias("@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } } From 944ee5839cf198b9d2fb99736d397dc98c1fa6e8 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Tue, 28 May 2024 17:36:18 +0530 Subject: [PATCH 05/15] Initial commit to create PR --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 711b2a1c..7518fbe4 100644 --- a/README.md +++ b/README.md @@ -568,3 +568,4 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). + From e42e3f2fe966773eede427f316e9702ed6ebb64d Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Wed, 29 May 2024 16:03:32 +0530 Subject: [PATCH 06/15] Fix https://github.com/cebe/yii2-openapi/issues/172 --- README.md | 1 - src/lib/openapi/ResponseSchema.php | 40 ++++++----- .../index.php | 14 ++++ .../index.yaml | 68 +++++++++++++++++++ .../pgsql/controllers/AccountController.php | 15 ++++ .../controllers/base/AccountController.php | 35 ++++++++++ tests/unit/IssueFixTest.php | 29 ++++++-- 7 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.php create mode 100644 tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.yaml create mode 100644 tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql/controllers/AccountController.php create mode 100644 tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql/controllers/base/AccountController.php diff --git a/README.md b/README.md index 7518fbe4..711b2a1c 100644 --- a/README.md +++ b/README.md @@ -568,4 +568,3 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). - diff --git a/src/lib/openapi/ResponseSchema.php b/src/lib/openapi/ResponseSchema.php index a0274449..a0efe944 100644 --- a/src/lib/openapi/ResponseSchema.php +++ b/src/lib/openapi/ResponseSchema.php @@ -7,6 +7,7 @@ namespace cebe\yii2openapi\lib\openapi; +use cebe\openapi\exceptions\UnresolvableReferenceException; use cebe\openapi\spec\MediaType; use cebe\openapi\spec\Operation; use cebe\openapi\spec\Reference; @@ -36,10 +37,10 @@ protected static function isObjectSchema($schema): bool protected static function isArraySchemaWithRefItems($schema): bool { return isset($schema->items) && $schema->items instanceof Reference && - (isset($schema->type) && $schema->type === 'array'); + (isset($schema->type) && $schema->type === 'array'); } - protected static function hasAttributesReference($schema):bool + protected static function hasAttributesReference($schema): bool { return isset($schema->properties['attributes']) && $schema->properties['attributes'] instanceof Reference; } @@ -58,11 +59,11 @@ protected static function schemaNameByRef($schemaOrReference): ?string } /** - * @param \cebe\openapi\spec\Operation $operation + * @param Operation $operation * @return array - * @throws \cebe\openapi\exceptions\UnresolvableReferenceException + * @throws UnresolvableReferenceException */ - public static function guessResponseRelations(Operation $operation):array + public static function guessResponseRelations(Operation $operation): array { if (!isset($operation->responses)) { return []; @@ -112,12 +113,12 @@ public static function guessResponseRelations(Operation $operation):array } /** - * @param \cebe\openapi\spec\Operation $operation + * @param Operation $operation * @param $actionType * @return string|null - * @throws \cebe\openapi\exceptions\UnresolvableReferenceException + * @throws UnresolvableReferenceException */ - public static function guessModelClass(Operation $operation, $actionType):?string + public static function guessModelClass(Operation $operation, $actionType): ?string { // first, check request body $requestBody = $operation->requestBody; @@ -162,13 +163,20 @@ public static function guessModelClass(Operation $operation, $actionType):?strin } /** - * @param \cebe\openapi\SpecObjectInterface $property + * @param SpecObjectInterface $property * @return array|null[] - * @throws \cebe\openapi\exceptions\UnresolvableReferenceException + * @throws UnresolvableReferenceException */ public static function guessModelClassFromJsonResource(SpecObjectInterface $property): array { - $schema = $property instanceof Reference? $property->resolve() : $property; + $schema = $property instanceof Reference ? $property->resolve() : $property; + + if (self::isObjectSchema($schema) && !self::hasAttributesReference($schema)) { # https://github.com/cebe/yii2-openapi/issues/172 + $name = self::schemaNameByRef($property); + if ($name !== null) { + return [$name, '', '', 'object']; + } + } if (self::isObjectSchema($schema) && self::hasAttributesReference($schema)) { $name = self::schemaNameByRef($schema->properties['attributes']); @@ -191,11 +199,11 @@ public static function guessModelClassFromJsonResource(SpecObjectInterface $prop } /** - * @param \cebe\openapi\spec\MediaType $content + * @param MediaType $content * @return array|null[] - * @throws \cebe\openapi\exceptions\UnresolvableReferenceException + * @throws UnresolvableReferenceException */ - public static function guessModelClassFromContent(MediaType $content):array + public static function guessModelClassFromContent(MediaType $content): array { /** @var $referencedSchema Schema */ if ($content->schema instanceof Reference) { @@ -258,9 +266,9 @@ public static function guessModelClassFromContent(MediaType $content):array * @param Operation $operation * @param $modelClass * @return null|array - * @throws \cebe\openapi\exceptions\UnresolvableReferenceException + * @throws UnresolvableReferenceException */ - public static function findResponseWrapper(Operation $operation, $modelClass):?array + public static function findResponseWrapper(Operation $operation, $modelClass): ?array { if (!isset($operation->responses)) { return null; diff --git a/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.php b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.php new file mode 100644 index 00000000..3debbb46 --- /dev/null +++ b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.php @@ -0,0 +1,14 @@ + '@specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.yaml', + 'generateUrls' => false, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => true, + 'generateMigrations' => false, + 'generateModelFaker' => false, // `generateModels` must be `true` in orde to use `generateModelFaker` as `true` +]; + diff --git a/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.yaml b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.yaml new file mode 100644 index 00000000..f309e31d --- /dev/null +++ b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.yaml @@ -0,0 +1,68 @@ +openapi: 3.0.3 + +info: + title: 'Proxy-Service' + version: 1.0.0 + +components: + + requestBodies: + + Account: + description: 'Create / update account' + required: true + content: + application/vnd.api+json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Account' + + responses: + + Account: + description: 'Returns one account by ID.' + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/Account' + + schemas: + + Account: + description: Account + type: object + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + description: account name + type: string + maxLength: 128 + +paths: + + '/accounts': + + post: + operationId: createAccount + summary: Create a account + description: Create account + requestBody: + $ref: '#/components/requestBodies/Account' + responses: + '201': + description: OK +# $ref: '#/components/responses/Account' + '400': + description: BodyParams must be an array. + '422': + description: Validation error. + tags: + - Accounts + diff --git a/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql/controllers/AccountController.php b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql/controllers/AccountController.php new file mode 100644 index 00000000..8c4f5280 --- /dev/null +++ b/tests/specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql/controllers/AccountController.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\CreateAction::class, + 'modelClass' => \app\models\Account::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index 04a31c2d..ca2a7972 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -307,12 +307,27 @@ public function test175BugAllOfWithMultipleDollarRefs() { $testFile = Yii::getAlias("@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/index.php"); $this->runGenerator($testFile, 'pgsql'); - $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ - 'recursive' => true, - ]); - $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql"), [ - 'recursive' => true, - ]); - $this->checkFiles($actualFiles, $expectedFiles); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/175_bug_allof_with_multiple_dollarrefs/pgsql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } + + // #172 https://github.com/cebe/yii2-openapi/issues/172 + // schema.yaml: requestBody has no effect + public function test172SchemayamlRequestBodyHasNoEffect() + { + $testFile = Yii::getAlias("@specs/issue_fix/172_schemayaml_requestbody_has_no_effect/index.php"); + $this->runGenerator($testFile, 'pgsql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/172_schemayaml_requestbody_has_no_effect/pgsql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); } } From b752fade92aed101f8a04ae900232427fabe6213 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Wed, 29 May 2024 16:47:54 +0530 Subject: [PATCH 07/15] Refactor --- src/lib/openapi/ResponseSchema.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/lib/openapi/ResponseSchema.php b/src/lib/openapi/ResponseSchema.php index a0efe944..06b53f23 100644 --- a/src/lib/openapi/ResponseSchema.php +++ b/src/lib/openapi/ResponseSchema.php @@ -170,20 +170,19 @@ public static function guessModelClass(Operation $operation, $actionType): ?stri public static function guessModelClassFromJsonResource(SpecObjectInterface $property): array { $schema = $property instanceof Reference ? $property->resolve() : $property; - - if (self::isObjectSchema($schema) && !self::hasAttributesReference($schema)) { # https://github.com/cebe/yii2-openapi/issues/172 - $name = self::schemaNameByRef($property); - if ($name !== null) { - return [$name, '', '', 'object']; - } - } - - if (self::isObjectSchema($schema) && self::hasAttributesReference($schema)) { - $name = self::schemaNameByRef($schema->properties['attributes']); - if ($name !== null) { - return [$name, '', '', 'object']; + if (self::isObjectSchema($schema)) { + if (self::hasAttributesReference($schema)) { + $name = self::schemaNameByRef($schema->properties['attributes']); + if ($name !== null) { + return [$name, '', '', 'object']; + } + return [null, null, null, null]; + } else { # https://github.com/cebe/yii2-openapi/issues/172 + $name = self::schemaNameByRef($property); + if ($name !== null) { + return [$name, '', '', 'object']; + } } - return [null, null, null, null]; } if (self::isArraySchemaWithRefItems($property)) { $ref = $property->items->resolve(); From 6d925852be8909f23eaf3ba1a5c3556f8b981bff Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Wed, 29 May 2024 20:14:34 +0530 Subject: [PATCH 08/15] IC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df87e47a..86e77ce8 100644 --- a/README.md +++ b/README.md @@ -564,3 +564,4 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). + From 58811f2823b439249d985cb489d6915e213c9568 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Wed, 29 May 2024 20:31:50 +0530 Subject: [PATCH 09/15] Create failing test case - WIP --- README.md | 1 - .../index.php | 14 +++++ .../index.yaml | 54 +++++++++++++++++++ tests/unit/IssueFixTest.php | 15 ++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.yaml diff --git a/README.md b/README.md index 7518fbe4..711b2a1c 100644 --- a/README.md +++ b/README.md @@ -568,4 +568,3 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). - diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.php new file mode 100644 index 00000000..b66f036b --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.php @@ -0,0 +1,14 @@ + '@specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => false, + 'generateModelFaker' => true, // `generateModels` must be `true` in orde to use `generateModelFaker` as `true` +]; + diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.yaml b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.yaml new file mode 100644 index 00000000..4fbb6f88 --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.yaml @@ -0,0 +1,54 @@ + +openapi: 3.0.3 + +info: + title: 'Proxy-Service' + version: 1.0.0 + +components: + + schemas: + + Mailing: + description: Mailing + type: object + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + description: name + type: string + maxLength: 128 + paymentMethodName: + type: string + + Contact: + description: Contact + type: object + required: + - id + - mailing + properties: + id: + type: integer + readOnly: true + mailing: + $ref: '#/components/schemas/Mailing' + active: + type: boolean + default: false + nickname: + type: string + +paths: + '/': + get: + operationId: opId + summary: summary + responses: + '200': + description: OK diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index ca2a7972..4399b0d2 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -330,4 +330,19 @@ public function test172SchemayamlRequestBodyHasNoEffect() ]); $this->checkFiles($actualFiles, $expectedFiles); } + + // https://github.com/cebe/yii2-openapi/issues/159 + public function test159BugGiiapiGeneratedRulesEmailid() + { + $this->changeDbToMariadb(); + $testFile = Yii::getAlias("@specs/issue_fix/159_bug_giiapi_generated_rules_emailid/index.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } } From ed97a318b9c2e01d7aeb5fbca5891911f777af9b Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 17:20:16 +0530 Subject: [PATCH 10/15] Fix https://github.com/cebe/yii2-openapi/issues/159 --- src/lib/ValidationRulesBuilder.php | 4 +- .../maria/models/BaseModelFaker.php | 144 ++++++++++++++++++ .../maria/models/Contact.php | 10 ++ .../maria/models/ContactFaker.php | 52 +++++++ .../maria/models/Mailing.php | 10 ++ .../maria/models/MailingFaker.php | 42 +++++ .../maria/models/base/Contact.php | 39 +++++ .../maria/models/base/Mailing.php | 29 ++++ 8 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/BaseModelFaker.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Contact.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/ContactFaker.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Mailing.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/MailingFaker.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Contact.php create mode 100644 tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Mailing.php diff --git a/src/lib/ValidationRulesBuilder.php b/src/lib/ValidationRulesBuilder.php index 035c8a3d..f3416237 100644 --- a/src/lib/ValidationRulesBuilder.php +++ b/src/lib/ValidationRulesBuilder.php @@ -142,7 +142,9 @@ private function addRulesByAttributeName(Attribute $attribute):void '~(url|site|website|href|link)~i' => 'url', ]; foreach ($patterns as $pattern => $validator) { - if (preg_match($pattern, strtolower($attribute->columnName))) { + if (empty($attribute->reference) # ignore column name based rules in case of reference/relation # https://github.com/cebe/yii2-openapi/issues/159 + && preg_match($pattern, strtolower($attribute->columnName))) { + $key = $attribute->columnName . '_' . $validator; $this->rules[$key] = new ValidationRule([$attribute->columnName], $validator); return; diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/BaseModelFaker.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Contact.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Contact.php new file mode 100644 index 00000000..8447fdaf --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Contact.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Contact(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->mailing_id = $faker->randomElement(\app\models\Mailing::find()->select("id")->column()); + $model->active = $faker->boolean; + $model->nickname = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } + + public static function dependentOn() + { + return [ + // just model class names + 'Mailing', + + ]; + } +} diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Mailing.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Mailing.php new file mode 100644 index 00000000..bb3f8821 --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/Mailing.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Mailing(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = substr($faker->text(128), 0, 128); + $model->paymentMethodName = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Contact.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Contact.php new file mode 100644 index 00000000..efbd8b32 --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Contact.php @@ -0,0 +1,39 @@ + [['nickname'], 'trim'], + 'required' => [['mailing_id'], 'required'], + 'mailing_id_integer' => [['mailing_id'], 'integer'], + 'mailing_id_exist' => [['mailing_id'], 'exist', 'targetRelation' => 'Mailing'], + 'active_boolean' => [['active'], 'boolean'], + 'active_default' => [['active'], 'default', 'value' => false], + 'nickname_string' => [['nickname'], 'string'], + ]; + } + + public function getMailing() + { + return $this->hasOne(\app\models\Mailing::class, ['id' => 'mailing_id']); + } +} diff --git a/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Mailing.php b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Mailing.php new file mode 100644 index 00000000..77049b23 --- /dev/null +++ b/tests/specs/issue_fix/159_bug_giiapi_generated_rules_emailid/maria/models/base/Mailing.php @@ -0,0 +1,29 @@ + [['name', 'paymentMethodName'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string', 'max' => 128], + 'paymentMethodName_string' => [['paymentMethodName'], 'string'], + ]; + } +} From 9c4b921a3344fc0511455c9c472f8423b96fc263 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 17:26:25 +0530 Subject: [PATCH 11/15] Fix style --- src/lib/ValidationRulesBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/ValidationRulesBuilder.php b/src/lib/ValidationRulesBuilder.php index f3416237..21119aa7 100644 --- a/src/lib/ValidationRulesBuilder.php +++ b/src/lib/ValidationRulesBuilder.php @@ -144,7 +144,6 @@ private function addRulesByAttributeName(Attribute $attribute):void foreach ($patterns as $pattern => $validator) { if (empty($attribute->reference) # ignore column name based rules in case of reference/relation # https://github.com/cebe/yii2-openapi/issues/159 && preg_match($pattern, strtolower($attribute->columnName))) { - $key = $attribute->columnName . '_' . $validator; $this->rules[$key] = new ValidationRule([$attribute->columnName], $validator); return; From 2bed3ca1e9a513acee6fb78050d7c8ff14be5a18 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 17:42:15 +0530 Subject: [PATCH 12/15] IC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df87e47a..86e77ce8 100644 --- a/README.md +++ b/README.md @@ -564,3 +564,4 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). + From 01846a87d3e3cfea291ade17a528adb4f19835e6 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 18:03:09 +0530 Subject: [PATCH 13/15] Fix https://github.com/cebe/yii2-openapi/issues/158 --- README.md | 1 - src/lib/ValidationRulesBuilder.php | 4 +- tests/specs/blog_v2/models/base/Post.php | 2 +- tests/specs/blog_v2/models/base/Tag.php | 2 +- tests/specs/blog_v2/models/base/User.php | 2 +- .../index.php | 14 ++ .../index.yaml | 40 +++++ .../maria/models/BaseModelFaker.php | 144 ++++++++++++++++++ .../maria/models/Mailing.php | 10 ++ .../maria/models/MailingFaker.php | 42 +++++ .../maria/models/base/Mailing.php | 34 +++++ .../postgres_custom/models/base/Custom.php | 1 - tests/unit/IssueFixTest.php | 15 ++ tests/unit/ValidatorRulesBuilderTest.php | 1 - 14 files changed, 305 insertions(+), 7 deletions(-) create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.php create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.yaml create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/BaseModelFaker.php create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/Mailing.php create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/MailingFaker.php create mode 100644 tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/base/Mailing.php diff --git a/README.md b/README.md index 7518fbe4..711b2a1c 100644 --- a/README.md +++ b/README.md @@ -568,4 +568,3 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). - diff --git a/src/lib/ValidationRulesBuilder.php b/src/lib/ValidationRulesBuilder.php index 21119aa7..3f3c1398 100644 --- a/src/lib/ValidationRulesBuilder.php +++ b/src/lib/ValidationRulesBuilder.php @@ -233,7 +233,9 @@ private function prepareTypeScope():void $this->typeScope['required'][$attribute->columnName] = $attribute->columnName; } - if ($attribute->phpType === 'string') { + if ($attribute->phpType === 'string' && + empty($attribute->enumValues) # don't apply trim on enum columns # https://github.com/cebe/yii2-openapi/issues/158 + ) { $this->typeScope['trim'][$attribute->columnName] = $attribute->columnName; } diff --git a/tests/specs/blog_v2/models/base/Post.php b/tests/specs/blog_v2/models/base/Post.php index aec49f28..44fe4275 100644 --- a/tests/specs/blog_v2/models/base/Post.php +++ b/tests/specs/blog_v2/models/base/Post.php @@ -29,7 +29,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['title', 'slug', 'lang', 'created_at'], 'trim'], + 'trim' => [['title', 'slug', 'created_at'], 'trim'], 'required' => [['title', 'category_id', 'active'], 'required'], 'category_id_integer' => [['category_id'], 'integer'], 'category_id_exist' => [['category_id'], 'exist', 'targetRelation' => 'Category'], diff --git a/tests/specs/blog_v2/models/base/Tag.php b/tests/specs/blog_v2/models/base/Tag.php index 15b383fb..f1a57778 100644 --- a/tests/specs/blog_v2/models/base/Tag.php +++ b/tests/specs/blog_v2/models/base/Tag.php @@ -21,7 +21,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['name', 'lang'], 'trim'], + 'trim' => [['name'], 'trim'], 'required' => [['name', 'lang'], 'required'], 'name_unique' => [['name'], 'unique'], 'name_string' => [['name'], 'string', 'max' => 100], diff --git a/tests/specs/blog_v2/models/base/User.php b/tests/specs/blog_v2/models/base/User.php index f75a9d97..195b5b5e 100644 --- a/tests/specs/blog_v2/models/base/User.php +++ b/tests/specs/blog_v2/models/base/User.php @@ -24,7 +24,7 @@ public static function tableName() public function rules() { return [ - 'trim' => [['login', 'email', 'password', 'role', 'created_at'], 'trim'], + 'trim' => [['login', 'email', 'password', 'created_at'], 'trim'], 'required' => [['login', 'email', 'password'], 'required'], 'login_unique' => [['login'], 'unique'], 'email_unique' => [['email'], 'unique'], diff --git a/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.php b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.php new file mode 100644 index 00000000..515b362c --- /dev/null +++ b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.php @@ -0,0 +1,14 @@ + '@specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => false, + 'generateModelFaker' => true, // `generateModels` must be `true` in orde to use `generateModelFaker` as `true` +]; + diff --git a/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.yaml b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.yaml new file mode 100644 index 00000000..b8268605 --- /dev/null +++ b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.yaml @@ -0,0 +1,40 @@ + +openapi: 3.0.3 + +info: + title: 'Proxy-Service' + version: 1.0.0 + +components: + + schemas: + + Mailing: + description: Mailing + type: object + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + description: name + type: string + maxLength: 128 + paymentMethodName: + type: string + enum: + - card + - cash + - ewallet + +paths: + '/': + get: + operationId: opId + summary: summary + responses: + '200': + description: OK diff --git a/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/BaseModelFaker.php b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/Mailing.php b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/Mailing.php new file mode 100644 index 00000000..bb3f8821 --- /dev/null +++ b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/Mailing.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Mailing(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = substr($faker->text(128), 0, 128); + $model->paymentMethodName = $faker->randomElement(['card','cash','ewallet']); + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/base/Mailing.php b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/base/Mailing.php new file mode 100644 index 00000000..2839c526 --- /dev/null +++ b/tests/specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria/models/base/Mailing.php @@ -0,0 +1,34 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string', 'max' => 128], + 'paymentMethodName_string' => [['paymentMethodName'], 'string'], + 'paymentMethodName_in' => [['paymentMethodName'], 'in', 'range' => [ + 'card', + 'cash', + 'ewallet', + ]], + ]; + } +} diff --git a/tests/specs/postgres_custom/models/base/Custom.php b/tests/specs/postgres_custom/models/base/Custom.php index f7bbc803..ea4bd5f7 100644 --- a/tests/specs/postgres_custom/models/base/Custom.php +++ b/tests/specs/postgres_custom/models/base/Custom.php @@ -26,7 +26,6 @@ public static function tableName() public function rules() { return [ - 'trim' => [['status', 'status_x'], 'trim'], 'num_integer' => [['num'], 'integer'], 'num_default' => [['num'], 'default', 'value' => 0], 'json1_default' => [['json1'], 'default', 'value' => []], diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index 4399b0d2..b6c7abdb 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -345,4 +345,19 @@ public function test159BugGiiapiGeneratedRulesEmailid() ]); $this->checkFiles($actualFiles, $expectedFiles); } + + // https://github.com/cebe/yii2-openapi/issues/158 + public function test158BugGiiapiGeneratedRulesEnumWithTrim() + { + $this->changeDbToMariadb(); + $testFile = Yii::getAlias("@specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/index.php"); + $this->runGenerator($testFile, 'maria'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/158_bug_giiapi_generated_rules_enum_with_trim/maria"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } } diff --git a/tests/unit/ValidatorRulesBuilderTest.php b/tests/unit/ValidatorRulesBuilderTest.php index 81d8a8fd..43343df6 100644 --- a/tests/unit/ValidatorRulesBuilderTest.php +++ b/tests/unit/ValidatorRulesBuilderTest.php @@ -42,7 +42,6 @@ public function testBuild() 'trim' => new ValidationRule([ 'title', 'article', - 'state', 'created_at', 'contact_email', 'required_with_def', From 404642a502f368b92b91b25326379a5c5bd60a7d Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 19:42:26 +0530 Subject: [PATCH 14/15] IC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df87e47a..86e77ce8 100644 --- a/README.md +++ b/README.md @@ -564,3 +564,4 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). + From 635f55f7d07981366e337a60a67dd78ee08b7aa8 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 30 May 2024 19:45:26 +0530 Subject: [PATCH 15/15] Fix https://github.com/cebe/yii2-openapi/issues/178 --- .github/workflows/test.yml | 2 +- README.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7d67d101..146e6518 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3'] # TODO use cache steps: diff --git a/README.md b/README.md index 7518fbe4..711b2a1c 100644 --- a/README.md +++ b/README.md @@ -568,4 +568,3 @@ Professional support, consulting as well as software development services are av https://www.cebe.cc/en/contact Development of this library is sponsored by [cebe.:cloud: "Your Professional Deployment Platform"](https://cebe.cloud). -