diff --git a/docker-compose.yml b/docker-compose.yml index f36f7f87..68a9c9bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: - maria tty: true mysql: - image: mysql:8 + image: mysql:8.0.37 ports: - '13306:3306' volumes: diff --git a/tests/.gitignore b/tests/.gitignore index cad23091..ceeb05b4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1 @@ -/tmp \ No newline at end of file +/tmp diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php new file mode 100644 index 00000000..e88d0ea9 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php @@ -0,0 +1,20 @@ +createTable('{{%deliveries}}', [ + 'id' => $this->primaryKey(), + 'title' => $this->text()->null(), + ]); + } + + public function down() + { + $this->dropTable('{{%deliveries}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php new file mode 100644 index 00000000..e6e9afe4 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php @@ -0,0 +1,20 @@ +createTable('{{%users}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->text()->notNull(), + ]); + } + + public function down() + { + $this->dropTable('{{%users}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php new file mode 100644 index 00000000..cf3b0845 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php @@ -0,0 +1,29 @@ +createTable('{{%webhooks}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->text()->null(), + 'user_id' => $this->integer()->null()->defaultValue(null), + 'redelivery_of' => $this->integer()->null()->defaultValue(null), + ]); + $this->addForeignKey('fk_webhooks_user_id_users_id', '{{%webhooks}}', 'user_id', '{{%users}}', 'id'); + $this->addForeignKey('fk_webhooks_redelivery_of_deliveries_id', '{{%webhooks}}', 'redelivery_of', '{{%deliveries}}', 'id'); + // TOOD add index names + $this->createIndex('...', '{{%webhooks}}', ['user_id', 'name'], true); + $this->createIndex('...', '{{%webhooks}}', ['redelivery_of', 'name'], true); + } + + public function down() + { + $this->dropForeignKey('fk_webhooks_redelivery_of_deliveries_id', '{{%webhooks}}'); + $this->dropForeignKey('fk_webhooks_user_id_users_id', '{{%webhooks}}'); + $this->dropTable('{{%webhooks}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/models/BaseModelFaker.php b/tests/specs/fk_col_name_index/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/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/fk_col_name_index/app/models/Delivery.php b/tests/specs/fk_col_name_index/app/models/Delivery.php new file mode 100644 index 00000000..1249e2b3 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/Delivery.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 Delivery(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->title = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/User.php b/tests/specs/fk_col_name_index/app/models/User.php new file mode 100644 index 00000000..9b837d6e --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/User.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 User(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/Webhook.php b/tests/specs/fk_col_name_index/app/models/Webhook.php new file mode 100644 index 00000000..e02ca284 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/Webhook.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 Webhook(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + $model->user_id = $faker->randomElement(\app\models\User::find()->select("id")->column()); + $model->redelivery_of = $faker->numberBetween(0, 1000000); + 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 + 'User', + 'Delivery', + + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/Delivery.php b/tests/specs/fk_col_name_index/app/models/base/Delivery.php new file mode 100644 index 00000000..ae7cbd83 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/Delivery.php @@ -0,0 +1,26 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/User.php b/tests/specs/fk_col_name_index/app/models/base/User.php new file mode 100644 index 00000000..d76c3f4d --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/User.php @@ -0,0 +1,27 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/Webhook.php b/tests/specs/fk_col_name_index/app/models/base/Webhook.php new file mode 100644 index 00000000..8746e8f0 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/Webhook.php @@ -0,0 +1,44 @@ + [['name'], 'trim'], + 'user_id_integer' => [['user_id'], 'integer'], + 'user_id_exist' => [['user_id'], 'exist', 'targetRelation' => 'User'], + 'redelivery_of_integer' => [['redelivery_of'], 'integer'], + 'redelivery_of_exist' => [['redelivery_of'], 'exist', 'targetRelation' => 'RedeliveryOf'], + 'name_string' => [['name'], 'string'], + ]; + } + + public function getUser() + { + return $this->hasOne(\app\models\User::class, ['id' => 'user_id']); + } + + public function getRedeliveryOf() + { + return $this->hasOne(\app\models\Delivery::class, ['id' => 'redelivery_of']); + } +} diff --git a/tests/specs/fk_col_name_index/fk_col_name_index.php b/tests/specs/fk_col_name_index/fk_col_name_index.php new file mode 100644 index 00000000..e952e245 --- /dev/null +++ b/tests/specs/fk_col_name_index/fk_col_name_index.php @@ -0,0 +1,13 @@ + '@specs/fk_col_name_index/fk_col_name_index.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/fk_col_name_index/fk_col_name_index.yaml b/tests/specs/fk_col_name_index/fk_col_name_index.yaml new file mode 100644 index 00000000..fb4976ce --- /dev/null +++ b/tests/specs/fk_col_name_index/fk_col_name_index.yaml @@ -0,0 +1,54 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: ID not in rules test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + User: + type: object + description: Test model for model code generation that should not contain id column in rules + required: + - id + - name + properties: + id: + type: integer + name: + type: string + Delivery: + x-table: deliveries + required: + - id + properties: + id: + type: integer + title: + type: string + Webhook: + x-indexes: + - 'unique:user_id,name' + - 'unique:redelivery_of,name' + type: object + description: example for x-fk-column-name + properties: + id: + type: integer + name: + type: string + user: + $ref: '#/components/schemas/User' # this will automatically create `user_id` column + redelivery_of: + allOf: + - $ref: '#/components/schemas/Delivery' + # this will automatically create `redelivery_of_id` column, but to avoid that use below extension + - x-fk-column-name: redelivery_of # this will create `redelivery_of` column instead of `redelivery_of_id` + diff --git a/tests/unit/ForeignKeyColumnNameTest.php b/tests/unit/ForeignKeyColumnNameTest.php index 24401ea5..119bfdf8 100644 --- a/tests/unit/ForeignKeyColumnNameTest.php +++ b/tests/unit/ForeignKeyColumnNameTest.php @@ -30,4 +30,20 @@ public function testIndex() $this->checkFiles($actualFiles, $expectedFiles); $this->runActualMigrations('mysql', 3); } + + public function testIndexForColumnWithCustomName() + { + // default DB is Mysql ---------------------------------- + + $testFile = Yii::getAlias("@specs/fk_col_name_index/fk_col_name_index.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/fk_col_name_index/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 3); + } }