From c7f7533b8c8b1d9dbb882db16b83b0f2dcffd83a Mon Sep 17 00:00:00 2001 From: Uldis Nelsons Date: Thu, 1 Feb 2024 11:00:12 +0200 Subject: [PATCH] Fix #534: Generating in model ENUM fields value constants, setter and getter methods --- CHANGELOG.md | 1 + src/generators/model/Generator.php | 58 +++++++++++++ src/generators/model/default/model.php | 64 ++++++++++++++ tests/generators/ModelGeneratorTest.php | 109 ++++++++++++++++++++++++ 4 files changed, 232 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a8b8e0da..d2922ef42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Yii Framework 2 gii extension Change Log - Bug #532: Return `ExitCode::USAGE` on command input validation error (egmsystems) - Enh #537: Generating rules for the fields with default values (manky) - Enh #542: Use the table name to create the relation (thiagotalma) +- Enh #534: Generating in model ENUM fields value constants, setter and getter methods (uldisn) 2.2.6 May 22, 2023 diff --git a/src/generators/model/Generator.php b/src/generators/model/Generator.php index d5c55e080..86abe3522 100644 --- a/src/generators/model/Generator.php +++ b/src/generators/model/Generator.php @@ -12,6 +12,7 @@ use yii\base\NotSupportedException; use yii\db\ActiveQuery; use yii\db\ActiveRecord; +use yii\db\ColumnSchema; use yii\db\Connection; use yii\db\Exception; use yii\db\Schema; @@ -307,6 +308,7 @@ public function generate() 'rules' => $this->generateRules($tableSchema), 'relations' => $tableRelations, 'relationsClassHints' => $this->generateRelationsClassHints($tableRelations, $this->generateQuery), + 'enum' => $this->getEnum($tableSchema->columns), ]; $files[] = new CodeFile( Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $modelClassName . '.php', @@ -509,6 +511,11 @@ public function generateRules($table) $rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]"; } + $columnsEnum = $this->getEnum($table->columns); + foreach ($columnsEnum as $fieldName => $columnEnum) { + $rules['enum-' . $fieldName] = "['" . $fieldName . "', 'in', 'range' => array_keys(self::" . $columnEnum['funcOptsName'] . '())]'; + } + $db = $this->getDbConnection(); // Unique indexes rules @@ -1188,6 +1195,57 @@ protected function isColumnAutoIncremental($table, $columns) return false; } + /** + * Prepares ENUM field values. + * + * @param ColumnSchema[] $columns + * + * @return array + */ + public function getEnum($columns) + { + $enum = []; + foreach ($columns as $column) { + if (!$this->isEnum($column)) { + continue; + } + + $columnCamelName = Inflector::id2camel($column->name, '_'); + $enum[$column->name]['funcOptsName'] = 'opts' . $columnCamelName; + $enum[$column->name]['isFunctionPrefix'] = 'is' . $columnCamelName; + $enum[$column->name]['setFunctionPrefix'] = 'set' . $columnCamelName . 'To'; + $enum[$column->name]['displayFunctionPrefix'] = 'display' . $columnCamelName; + $enum[$column->name]['columnName'] = $column->name; + $enum[$column->name]['values'] = []; + + foreach ($column->enumValues as $value) { + + $constantName = strtoupper(Inflector::slug($column->name . ' ' . $value, '_')); + $label = Inflector::camel2words($value); + + $enum[$column->name]['values'][] = [ + 'value' => $value, + 'constName' => $constantName, + 'label' => $label, + 'functionSuffix' => Inflector::id2camel(Inflector::slug($value)) + ]; + } + } + + return $enum; + } + + /** + * Checks if column is of ENUM type. + * + * @param ColumnSchema $column Column instance + * @return bool + */ + protected function isEnum($column) + { + return !empty($column->enumValues) || stripos($column->dbType, 'ENUM') === 0; + } + /** * Returns the class name resolution * @param string $class diff --git a/src/generators/model/default/model.php b/src/generators/model/default/model.php index f35676362..e9789aca7 100644 --- a/src/generators/model/default/model.php +++ b/src/generators/model/default/model.php @@ -3,6 +3,7 @@ * This is the template for generating the model class of a specified table. */ +/** @var $enum array list of ENUM fields */ /** @var yii\web\View $this */ /** @var yii\gii\generators\model\Generator $generator */ /** @var string $tableName full table name */ @@ -36,6 +37,20 @@ */ class extends baseClass, '\\') . "\n" ?> { + + + /** + * ENUM field values + */ + $columnData) { + foreach ($columnData['values'] as $enumValue){ + echo ' const ' . $enumValue['constName'] . ' = \'' . $enumValue['value'] . '\';' . PHP_EOL; + } + } +endif +?> + /** * {@inheritdoc} */ @@ -99,4 +114,53 @@ public static function find() return new (get_called_class()); } + + + $columnData): ?> + + /** + * column ENUM value labels + * @return string[] + */ + public static function () + { + return [ + $value): ?> +enableI18N) { + echo ' self::' . $value['constName'] . ' => Yii::t(\'' . $generator->messageCategory . '\', \'' . $value['value'] . "'),\n"; + } else { + echo ' self::' . $value['constName'] . ' => \'' . $value['value'] . "',\n"; + } + ?> + + ]; + } + + $columnData): ?> + + /** + * @return string + */ + public function () + { + return self::()[$this->]; + } + + + /** + * @return bool + */ + public function () + { + return $this-> === self::; + } + + public function () + { + $this-> = self::; + } + + + } diff --git a/tests/generators/ModelGeneratorTest.php b/tests/generators/ModelGeneratorTest.php index 7a2ca6d46..bb1d9f6d4 100644 --- a/tests/generators/ModelGeneratorTest.php +++ b/tests/generators/ModelGeneratorTest.php @@ -1,6 +1,8 @@ template = 'default'; + $generator->tableName = 'category_photo'; + + $tableSchema = $this->createEnumTableSchema(); + $params = [ + 'tableName' => $tableSchema->name, + 'className' => 'TestEnumModel', + 'queryClassName' => false, + 'tableSchema' => $tableSchema, + 'properties' => [], + 'labels' => $generator->generateLabels($tableSchema), + 'rules' => $generator->generateRules($tableSchema), + 'relations' => [], + 'relationsClassHints' => [], + 'enum' => $generator->getEnum($tableSchema->columns), + ]; + $codeFile = $generator->render('model.php', $params); + + /** + * Fix class code for eval - remove ?php, namespace and use Yii + */ + $classCode = str_replace('createEnumTableSchema(); + + /** test assigning and method is... */ + $testEnumModel->type = \TestEnumModel::TYPE_CLIENT; + $this->assertTrue($testEnumModel->isTypeClient()); + $this->assertFalse($testEnumModel->isTypeConsignees()); + + $testEnumModel->type = \TestEnumModel::TYPE_CONSIGNEES; + $this->assertFalse($testEnumModel->isTypeClient()); + $this->assertTrue($testEnumModel->isTypeConsignees()); + $this->assertEquals(\TestEnumModel::TYPE_CONSIGNEES,$testEnumModel->displayType()); + + /** test validate */ + $this->assertTrue($testEnumModel->validate()); + $testEnumModel->type = '11111'; + $this->assertFalse($testEnumModel->validate()); + + } + + public function createEnumTableSchema() + { + $schema = new TableSchema(); + $schema->name = 'company_type'; + $schema->fullName = 'company_type'; + $schema->primaryKey = ['id']; + $schema->columns = [ + 'id' => new ColumnSchema([ + 'name' => 'id', + 'allowNull' => false, + 'type' => 'smallint', + 'phpType' => 'integer', + 'dbType' => 'smallint(5) unsigned', + 'size' => 5, + 'precision' => 5, + 'isPrimaryKey' => true, + 'autoIncrement' => true, + 'unsigned' => true, + 'comment' => '' + ]), + 'type' => new ColumnSchema([ + 'name' => 'type', + 'allowNull' => true, + 'type' => 'string', + 'phpType' => 'string', + 'dbType' => 'enum(\'Client\',\'Consignees\',\'Car cleaner\')', + 'enumValues' => [ + 0 => 'Client', + 1 => 'Consignees', + 2 => 'Car cleaner', + ], + 'size' => null, + 'precision' => null, + 'isPrimaryKey' => false, + 'autoIncrement' => false, + 'unsigned' => false, + 'comment' => '' + ]), + ]; + + return $schema; + } }