Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented enum #434

Merged
merged 23 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/generators/model/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
64 changes: 64 additions & 0 deletions src/generators/model/default/model.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -36,6 +37,20 @@
*/
class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') . "\n" ?>
{

<?php if (!empty($enum)): ?>
/**
* ENUM field values
*/
<?php
foreach($enum as $columnName => $columnData) {
foreach ($columnData['values'] as $enumValue){
echo ' const ' . $enumValue['constName'] . ' = \'' . $enumValue['value'] . '\';' . PHP_EOL;
}
}
endif
?>

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -99,4 +114,53 @@ public static function find()
return new <?= $queryClassFullName ?>(get_called_class());
}
<?php endif; ?>

<?php if ($enum): ?>
<?php foreach ($enum as $columnName => $columnData): ?>

/**
* column <?= $columnName ?> ENUM value labels
* @return string[]
*/
public static function <?= $columnData['funcOptsName'] ?>()
{
return [
<?php foreach ($columnData['values'] as $k => $value): ?>
<?php
if ($generator->enableI18N) {
echo ' self::' . $value['constName'] . ' => Yii::t(\'' . $generator->messageCategory . '\', \'' . $value['value'] . "'),\n";
} else {
echo ' self::' . $value['constName'] . ' => \'' . $value['value'] . "',\n";
}
?>
<?php endforeach; ?>
];
}
<?php endforeach; ?>
<?php foreach ($enum as $columnName => $columnData): ?>

/**
* @return string
*/
public function <?= $columnData['displayFunctionPrefix'] ?>()
{
return self::<?= $columnData['funcOptsName'] ?>()[$this-><?=$columnName?>];
}
<?php foreach ($columnData['values'] as $enumValue): ?>

/**
* @return bool
*/
public function <?= $columnData['isFunctionPrefix'] . $enumValue['functionSuffix'] ?>()
{
return $this-><?= $columnName ?> === self::<?= $enumValue['constName'] ?>;
}

samdark marked this conversation as resolved.
Show resolved Hide resolved
public function <?= $columnData['setFunctionPrefix'] . $enumValue['functionSuffix'] ?>()
{
$this-><?= $columnName ?> = self::<?= $enumValue['constName'] ?>;
}
<?php endforeach; ?>
<?php endforeach; ?>
<?php endif; ?>
}
109 changes: 109 additions & 0 deletions tests/generators/ModelGeneratorTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace yiiunit\gii\generators;

use yii\db\mysql\ColumnSchema;
use yii\db\TableSchema;
use yii\gii\generators\model\Generator as ModelGenerator;
use yiiunit\gii\GiiTestCase;

Expand Down Expand Up @@ -484,4 +486,111 @@ public function testGenerateProperties($tableName, $columns)
}

}

public function testEnum()
{
$generator = new ModelGenerator();
$generator->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('<?php', '', $codeFile);
$classCode = str_replace('namespace app\models;', '', $classCode);
$classCode = str_replace('use Yii;', '', $classCode);

/**
* Add method getTableSchema for setting test schema
*/
$classCode = substr($classCode, 0, strrpos($classCode, "\n"));
$classCode = substr($classCode, 0, strrpos($classCode, "\n"));
$classCode .= '
public static $testTableSchema;
public static function getTableSchema(){
return self::$testTableSchema;
}
}
';
if (!class_exists('TestEnumModel')) {
eval($classCode);
uldisn marked this conversation as resolved.
Show resolved Hide resolved
}

$testEnumModel = new \TestEnumModel();
$testEnumModel::$testTableSchema = $this->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());

uldisn marked this conversation as resolved.
Show resolved Hide resolved
}

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;
}
}
Loading